﻿using ezCloud.Api.Models;
using ezCloud.Data;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace ezCloud.Api.Common
{
    public class PlanListConstantlyFormula
    {
        private ezCloudDataContext context = new ezCloudDataContext();
        public string Name { get; set; }
        public DateRange Range { get; set; }
        public int Priority { get; set; }
        public string FormulaUnit { get; set; }
        public decimal ValueBefore { get; set; }
        public decimal ValueAfter { get; set; }
        public decimal FormulaValue { get; set; }
        public int FormulaPeriod { get; set; }
        public IDictionary<int, decimal> FormulaEarlyCheckIn { get; set; }
        public IDictionary<int, decimal> FormulaLateCheckOut { get; set; }
        public List<DateTime> NotAvailableDays { get; set; }
        public PlanViewModel Plan { get; set; }
        public List<String> constantlyFormulaException { get; set; }

        public PlanListConstantlyFormula()
        {
        }

        public PlanListConstantlyFormula(PlanViewModel plan, string name, DateRange range, int priority, string formulaUnit, decimal valueBefore, decimal formulaValue, int formulaPeriod)
        {
            Plan          = plan;
            Range         = range;
            Name          = name;
            Priority      = priority;
            FormulaUnit   = formulaUnit;
            FormulaValue  = formulaValue;
            FormulaPeriod = formulaPeriod;
            ValueBefore   = valueBefore;
            ValueAfter    = Excute(valueBefore, formulaValue, formulaPeriod);
        }

        public decimal Excute(decimal valueBefore, decimal formulaValue, int formulaPeriod)
        {
            return valueBefore + formulaValue * formulaPeriod;
        }
    }

    public class PlanListFullDayFormula
    {
        public PlanViewModel plan { get; set; }
        public DateRange range { get; set; }
        public PlanListConstantlyFormula formula { get; set; }
        public Dictionary<String, String> fullDayFormulaWarning = new Dictionary<string, string>();
        public Dictionary<DateTime, String> fullDayFormulaException = new Dictionary<DateTime, string>();
    }

    public class PlanListHourlyFormula
    {
        public List<PlanListConstantlyFormula> availableHourlyFormula { get; set; }
        public PlanListConstantlyFormula finalHourlyFormula { get; set; }
        public Dictionary<String, String> hourlyFormulaWarning = new Dictionary<string, string>();

        public PlanListHourlyFormula()
        {
        }
    }

    public class AvailableDaysInWeek
    {
        public PlanViewModel Plan { get; set; }
        public List<Int32> AvailableDays { get; set; }

        public AvailableDaysInWeek()
        {
        }
    }

    public class PlanListExtraTraveller
    {
        public PlanViewModel Plan { get; set; }
        public int Extra { get; set; }
        public decimal DefaultPrice { get; set; }
        public decimal ExtraPrice { get; set; }
    }

    public class Range
    {
        public DateTime Start { get; set; }
        public DateTime End { get; set; }

        public Range(DateTime start, DateTime end)
        {
            Start = start;
            End = end;
        }
    }

    public struct DateTimeSpan
    {
        private readonly int years;
        private readonly int months;
        private readonly int days;
        private readonly int hours;
        private readonly int minutes;
        private readonly int seconds;
        private readonly int milliseconds;

        public DateTimeSpan(int years, int months, int days, int hours, int minutes, int seconds, int milliseconds)
        {
            this.years        = years;
            this.months       = months;
            this.days         = days;
            this.hours        = hours;
            this.minutes      = minutes;
            this.seconds      = seconds;
            this.milliseconds = milliseconds;
        }

        public int Years { get { return years; } }
        public int Months { get { return months; } }
        public int Days { get { return days; } }
        public int Hours { get { return hours; } }
        public int Minutes { get { return minutes; } }
        public int Seconds { get { return seconds; } }
        public int Milliseconds { get { return milliseconds; } }

        private enum Phase
        { Years, Months, Days, Done }
    }

    public class PlanListDateRange : IRange<DateTime>
    {

        public DateTime Start { get; set; }
        public DateTime End { get; set; }

        private static ezCloudDataContext context;
        private static UserProfile currentClientUser;
        private static Hotels currentHotel;

        public int month, week, day, hour, minute, totalHour, hotelTotalWorkTime;
        public DateRange rangeHour, rangeDay, rangeWeek, rangeMonth;
        public bool flagRoundUp                 = false;
        public decimal totalPrice               = 0.0M;
        public decimal actualTotalPrice         = 0.0M;
        public decimal discountPercentageAmount = 0.0M;
        public decimal discountFlatAmount       = 0.0M;
        public decimal focAmount                = 0.0M;
        

        public PlanListPreviewModel model;
        public List<PlanListConstantlyFormula> planListConstantlyFormula = new List<PlanListConstantlyFormula>();
        public PlanListHourlyFormula planListHourlyFormula               = new PlanListHourlyFormula();
        public List<PlanListFullDayFormula> planListFullDayFormula       = new List<PlanListFullDayFormula>();
        
        public PlanListExtraTraveller extraAdults { get; set; }
        public PlanListExtraTraveller extraChildren { get; set; }
        public PlanListDateRange actualPlanListDateRange { get; set; }

        public PlanListDateRange(DateTime start, DateTime end)
        {
            Start             = start;
            End               = end;
            context           = new ezCloudDataContext();
            currentClientUser = Common.UserUtitily.getUserProfile();
            currentHotel      = context.Hotels.Where(ht => ht.HotelId == currentClientUser.HotelId).FirstOrDefault();
            this.rangeMonth   = null;
            this.rangeWeek    = null;
            this.rangeDay     = null;
            this.rangeHour    = null;
        }

        public bool Includes(DateTime value)
        {
            return (Start <= value) && (value <= End);
        }

        public bool Includes(IRange<DateTime> range)
        {
            return (Start <= range.Start) && (range.End <= End);
        }

        public bool Includes(TimeSpan timeSpan)
        {
            return (Start.TimeOfDay <= timeSpan) && (timeSpan <= End.TimeOfDay);
        }

        public IEnumerable<DateTime> EachDay(IRange<DateTime> range)
        {
            for (var day = range.Start; day.Date <= range.End.Date; day = day.AddDays(1))
                yield return day;
        }

        public IEnumerable<DateTime> EachDay(Range range)
        {
            for (var day = range.Start; day.Date <= range.End.Date; day = day.AddDays(1))
                yield return day;
        }

        public IEnumerable<DateRange> EachRangeDay(IRange<DateTime> range)
        {
            for (var day = new DateRange(range.Start, range.Start.AddDays(1)); day.End.Date <= range.End.Date; day = new DateRange(day.Start.AddDays(1), day.End.AddDays(1)))
                yield return day;
        }


        public void CalculateTimeDuration()
        {
            var hotelCheckOutTime      = currentHotel.FullDayCheckoutTime;
            var hotelTotalHourTemp     = currentHotel.FullDayCheckoutTime.Subtract(currentHotel.FullDayCheckinTime).Duration().TotalMinutes;
            this.hotelTotalWorkTime    = 24 * 60 - (int)hotelTotalHourTemp;
            var oneDayHotelWorkingTime = hotelTotalWorkTime;

            var oneHour      = 60;
            var oneDay       = oneDayHotelWorkingTime;
            var oneWeek      = 7 * 24 * 60;
            var oneMonth     = 30 * 24 * 60;
            var oneMonthHour = 30 * 24;
            var oneWeekHour  = 7 * 24;
            var oneDayHour   = oneDayHotelWorkingTime / 60;

            this.minute    = (int)(this.End - this.Start).TotalMinutes;
            this.totalHour = (int)(this.End - this.Start).TotalHours;

            var plan = this.GetPlanDetail();

            if (plan.UseMonthlyPrice == true)
            {
                this.month  = this.minute / oneMonth;
                this.minute = this.minute - this.month * oneMonth;
            }
            if (plan.UseWeeklyPrice == true)
            {
                this.week   = this.minute / oneWeek;
                this.minute = this.minute - this.week * oneWeek;
            }
            if (plan.UseFullDayPrice == true)
            {
                this.day    = this.minute / oneDay;
                this.minute = this.minute - this.day * oneDay;
            }
            if (plan.UseHourlyPrice == true)
            {
                this.hour   = this.minute / oneHour;
                this.minute = this.minute - this.hour * oneHour;
                if (this.minute >= currentHotel.MinutesToRoundUp)
                {
                    flagRoundUp = true;
                    this.hour   = this.hour + 1;
                }
                this.minute = 0;
            }
            

            if (this.month > 0)
            {
                this.rangeMonth = new DateRange(this.Start, this.Start.AddHours(oneMonthHour * this.month));
                this.Start      = this.Start.AddHours(oneMonthHour * this.month);
            }
            if (this.week > 0)
            {
                this.rangeWeek = new DateRange(this.Start, this.Start.AddHours(oneWeekHour * this.week));
                this.Start     = this.Start.AddHours(oneWeekHour * this.week);
            }
            this.rangeDay = new DateRange(this.Start, this.End);
            if (this.day > 1)
            {
                this.Start = this.Start.AddMinutes(this.day * oneDay);
            }
            this.rangeHour = new DateRange(this.Start, this.End);
           
        }

        public AvailableDaysInWeek CalculatePlanAvailableDaysInWeek(PlanViewModel plan)
        {
            AvailableDaysInWeek availableDaysInWeek = new AvailableDaysInWeek();
            availableDaysInWeek.Plan = plan;
            availableDaysInWeek.AvailableDays = new List<Int32>();
            int index = 0;
            for (int i = 0; i < model.currentRoomType.planList.Count; i++)
            {
                if (model.currentRoomType.planList[i].RoomPriceId == plan.RoomPriceId)
                {
                    index = i;
                    break;
                }
            }

            Dictionary<int, bool> appliedDays = new Dictionary<int, bool>();
            appliedDays.Add(0, model.currentRoomType.planDetailList[index].PlanSchedule.ApplyOnSunday);
            appliedDays.Add(1, model.currentRoomType.planDetailList[index].PlanSchedule.ApplyOnMonday);
            appliedDays.Add(2, model.currentRoomType.planDetailList[index].PlanSchedule.ApplyOnTuesday);
            appliedDays.Add(3, model.currentRoomType.planDetailList[index].PlanSchedule.ApplyOnWednesday);
            appliedDays.Add(4, model.currentRoomType.planDetailList[index].PlanSchedule.ApplyOnThursday);
            appliedDays.Add(5, model.currentRoomType.planDetailList[index].PlanSchedule.ApplyOnFriday);
            appliedDays.Add(6, model.currentRoomType.planDetailList[index].PlanSchedule.ApplyOnSaturday);

            foreach (KeyValuePair<int, bool> appliedDay in appliedDays)
            {
                if (appliedDay.Value == true)
                {
                    availableDaysInWeek.AvailableDays.Add(appliedDay.Key);
                }
            }

            return availableDaysInWeek;
        }

        // CÔNG THỨC TÍNH THÁNG VÀ TUẦN CHƯA HOÀN THIỆN DO CHƯA ĐỦ TRI THỨC
        public void CalculateConstantlyFormula()
        {
            decimal valueBefore = 0.0M;

            if (this.month > 0)
            {
                PlanViewModel rangeMonthPlan = new PlanViewModel();
                decimal rangeMonthPrice = 0.0M;
                bool isPlanNull = false;
                if (this.model.RoomPriceId > 0)
                {
                    rangeMonthPlan = this.GetPlan();
                }
                if (rangeMonthPlan == null)
                {
                    isPlanNull = true;
                }
                else
                {
                    for (int i = 0; i < model.currentRoomType.planDetailList.Count; i++)
                    {
                        if (model.currentRoomType.planDetailList[i].Plan.RoomPriceId == this.model.RoomPriceId)
                        {
                            rangeMonthPrice = model.currentRoomType.planDetailList[i].UseMonthlyPrice.price ?? 0.0M;
                            break;
                        }
                    }
                }

                if (!isPlanNull)
                {
                    PlanListConstantlyFormula monthlyFormula = new PlanListConstantlyFormula(rangeMonthPlan, "MONTHLY_PRICE", rangeMonth, 1, "MONTH(S)", valueBefore, rangeMonthPrice, this.month);
                    valueBefore = monthlyFormula.ValueAfter;
                    this.planListConstantlyFormula.Add(monthlyFormula);
                }
            }

            if (this.week > 0)
            {
                PlanViewModel rangeWeekPlan = new PlanViewModel();
                decimal rangeWeekPrice = 0.0M;
                bool isWeekPlanNull = false;
                if (this.model.RoomPriceId > 0)
                {
                    rangeWeekPlan = this.GetPlan();
                }
                if (rangeWeekPlan == null)
                {
                    isWeekPlanNull = true;
                }
                else
                {

                    for (int i = 0; i < model.currentRoomType.planDetailList.Count; i++)
                    {
                        if (model.currentRoomType.planDetailList[i].Plan.RoomPriceId == rangeWeekPlan.RoomPriceId)
                        {
                            rangeWeekPrice = model.currentRoomType.planDetailList[i].UseWeeklyPrice.price ?? 0.0M;
                            break;
                        }
                    }
                }

                if (!isWeekPlanNull)
                {
                    PlanListConstantlyFormula weeklyFormula = new PlanListConstantlyFormula(rangeWeekPlan, "WEEKLY_PRICE", rangeWeek, 2, "WEEK(S)", valueBefore, rangeWeekPrice, this.week);
                    valueBefore = weeklyFormula.ValueAfter;
                    this.planListConstantlyFormula.Add(weeklyFormula);
                }
            }
            if (this.planListConstantlyFormula.Count > 0)
            {
                this.totalPrice = this.planListConstantlyFormula[this.planListConstantlyFormula.Count - 1].ValueAfter;
            }
        }

        public RoomPrices GetPlanDetail()
        {
            var plan = currentHotel.RoomPricesList.Where(rp => rp.RoomPriceId == model.RoomPriceId).FirstOrDefault();
            return plan;
        }

        public PlanViewModel GetPlan()
        {
            var plan             = currentHotel.RoomPricesList.Where(rp => rp.RoomPriceId == model.RoomPriceId).FirstOrDefault();
            var result           = new PlanViewModel();
            result.RoomPriceId   = plan.RoomPriceId;
            result.RoomPriceName = plan.RoomPriceName;
            result.Priority      = plan.Priority;
            result.HotelId       = plan.HotelId ?? default(int);
            result.RoomTypeId    = plan.RoomTypeId ?? default(int);
            result.isActive      = plan.IsActive;
            return result;
        }

        public PlanViewModel DetermineWhichPlanIsApplied(string policyName)
        {
            PlanViewModel result = null;
            for (int i = 0; i < this.model.currentRoomType.planList.Count; i++)
            {
                if (this.model.currentRoomType.planList[i].isActive == true)
                {
                    System.Reflection.PropertyInfo usePolicyPropertyInfo = model.currentRoomType.planDetailList[i].GetType().GetProperty(policyName);
                    var planDetailItem = usePolicyPropertyInfo.GetValue(model.currentRoomType.planDetailList[i], null);
                    System.Reflection.PropertyInfo isUsedPropertyInfo = planDetailItem.GetType().GetProperty("isUsed");
                    if ((bool)isUsedPropertyInfo.GetValue(planDetailItem, null) == true)
                    {
                        result = this.model.currentRoomType.planList[i];
                        break;
                    }
                }
            }
            return result;
        }

        public PlanViewModel DetermineWhichPlanIsApplied(DateTime day)
        {
            PlanViewModel result = null;
            bool determined = false;
            for (int i = 0; i < model.currentRoomType.planList.Count; i++)
            {
                if (CalculatePlanAvailableDaysInWeek(model.currentRoomType.planList[i]).AvailableDays.Contains((int)day.DayOfWeek))
                {
                    for (int j = 0; j < model.currentRoomType.planDetailList.Count; j++)
                    {
                        if (this.model.currentRoomType.planDetailList[j].Plan.RoomPriceId == model.currentRoomType.planList[i].RoomPriceId)
                        {
                            result = this.model.currentRoomType.planList[i];
                            determined = true;
                            break;
                        }
                    }
                    if (determined == true)
                    {
                        break;
                    }
                }
            }
            return result;
        }

        public PlanViewModel DetermineWhichPlanIsApplied(DateTime day, string policyName)
        {
            PlanViewModel result = null;
            for (int i = 0; i < this.model.currentRoomType.planList.Count; i++)
            {
                if (this.DetermineWhichPlanIsApplied(day) != null && this.DetermineWhichPlanIsApplied(policyName) != null && this.model.currentRoomType.planList[i].RoomPriceId == this.DetermineWhichPlanIsApplied(day).RoomPriceId && this.model.currentRoomType.planList[i].RoomPriceId == this.DetermineWhichPlanIsApplied(policyName).RoomPriceId)
                {
                    result = this.model.currentRoomType.planList[i];
                    break;
                }
            }
            return result;
        }

        public class DateTimeRange
        {
            public DateTime CheckInTime { get; set; }
            public DateTime CheckOutTime { get; set; }
        }
        // We all already known: hotel one day time != normal (24h) one day time. So we have to convert normal time range to hotel time range 
        public List<DateRange> RebuildRangeDay(DateRange rangeDay)
        {
            var normalDateTimeRanges = new List<DateTimeRange>();
            rangeDay.Start = rangeDay.Start.AddMinutes(currentHotel.TimeZoneOffset);
            rangeDay.End = rangeDay.End.AddMinutes(currentHotel.TimeZoneOffset);
            foreach(DateRange range in EachRangeDay(rangeDay))
            {
                var dateTimeRange = new DateTimeRange();
                dateTimeRange.CheckInTime = range.Start.Date + currentHotel.FullDayCheckinTime;
                dateTimeRange.CheckOutTime = range.End.Date + currentHotel.FullDayCheckoutTime;
                normalDateTimeRanges.Add(dateTimeRange);
            }

            if (normalDateTimeRanges.Count == 0)
            {
                var dateTimeRange = new DateTimeRange();
                dateTimeRange.CheckInTime = rangeDay.Start.Date + currentHotel.FullDayCheckinTime;
                dateTimeRange.CheckOutTime = rangeDay.End.Date + currentHotel.FullDayCheckoutTime;
                normalDateTimeRanges.Add(dateTimeRange);
            }

            for (int i = 0; i < normalDateTimeRanges.Count; i++)
            {
                normalDateTimeRanges[i].CheckInTime = normalDateTimeRanges[i].CheckInTime.AddMinutes(-currentHotel.TimeZoneOffset);
                normalDateTimeRanges[i].CheckOutTime = normalDateTimeRanges[i].CheckOutTime.AddMinutes(-currentHotel.TimeZoneOffset);
            }

            List<DateRange> hotelDateTimeRanges = new List<DateRange>();
            if (normalDateTimeRanges.Count > 0)
            {
                for (int i = 0; i < normalDateTimeRanges.Count; i++)
                {
                    DateRange newDateRange = new DateRange(normalDateTimeRanges[i].CheckInTime, normalDateTimeRanges[i].CheckOutTime);
                    hotelDateTimeRanges.Add(newDateRange);
                }
            }

            rangeDay.Start = rangeDay.Start.AddMinutes(-currentHotel.TimeZoneOffset);
            rangeDay.End = rangeDay.End.AddMinutes(-currentHotel.TimeZoneOffset);

            hotelDateTimeRanges[0].Start = rangeDay.Start;
            hotelDateTimeRanges[hotelDateTimeRanges.Count - 1].End = rangeDay.End;

            return hotelDateTimeRanges;
        }

        public void CalculateFullDayFormula()
        {
            var plan = GetPlan();
            PlanDetailViewModel planDetail = null;
            for (int i = 0; i < this.model.currentRoomType.planDetailList.Count; i++)
            {
                if (model.currentRoomType.planDetailList[i].Plan.RoomPriceId == plan.RoomPriceId)
                {
                    planDetail = model.currentRoomType.planDetailList[i];
                    break;
                }
            }
            var defaultFormula          = new PlanListConstantlyFormula(plan, "FULL_DAY_PRICE", rangeDay, 3, "DAY(S)", this.totalPrice, planDetail.UseFullDayPrice.price ?? 0.0M, 1);
            var fullDayEarlyCheckInList = context.RoomPriceAdjustment.Where(rpa => rpa.HotelId == currentClientUser.HotelId && rpa.RoomPriceId == plan.RoomPriceId && rpa.AdjustmentCode == "EARLY_CHECKIN_FULL_DAY").OrderBy(o => o.NumberOfHour).ToList();
            if (this.rangeDay != null)
            {
                var newDateRange = this.RebuildRangeDay(this.rangeDay);
                int i = 0;
                foreach (DateRange range in newDateRange)
                {
                    var formula                 = new PlanListFullDayFormula();
                    formula.range               = range;
                    formula.plan                = plan;
                    formula.formula             = defaultFormula;
                    formula.formula.ValueAfter += formula.formula.FormulaValue;
                    if (i == 0 || i == newDateRange.Count - 1)
                    {
                        formula = this.CalculatePlanInRangeDay(range, plan, fullDayEarlyCheckInList, planDetail);
                    }                                            
                        
                    if (formula != null && formula.formula != null)
                    {
                        planListFullDayFormula.Add(formula);
                        this.totalPrice = formula.formula.ValueAfter;
                    }
                }
            }
            else
            {
                return;
            }           
        }

        public PlanListFullDayFormula CalculatePlanInRangeDay(DateRange rangeDay, PlanViewModel plan, List<RoomPriceAdjustment> fullDayEarlyCheckInList, PlanDetailViewModel planDetail)
        {
            var result = new PlanListFullDayFormula();
            int rangeDayMinutes = (int)(rangeDay.End - rangeDay.Start).TotalMinutes;
            
            // (> OR >=)            
            if (rangeDayMinutes >= currentHotel.MinutesToRoundUp)
            {                                
                if (plan == null)
                {
                    return result;
                }
                else
                {
                    result.plan                         = plan;
                    result.range                        = rangeDay;
                    result.formula                      = new PlanListConstantlyFormula(plan, "FULL_DAY_PRICE", rangeDay, 3, "DAY(S)", this.totalPrice, planDetail.UseFullDayPrice.price ?? 0.0M, 1);
                    var valueAfterTempFullDay           = this.totalPrice;
                    bool isFullDayEarlyCheckInToFullDay = false;
                    bool isFullDayLateCheckOutToFullDay = false;

                    TimeSpan checkInTime  = currentHotel.FullDayCheckinTime;
                    TimeSpan checkOutTime = currentHotel.FullDayCheckoutTime;
                    DateTime startFullDay = rangeDay.Start.AddMinutes(currentHotel.TimeZoneOffset).Date + checkInTime;
                    DateTime endFullDay   = rangeDay.End.AddMinutes(currentHotel.TimeZoneOffset).Date + checkOutTime;
                   
                    startFullDay = startFullDay.AddMinutes(-currentHotel.TimeZoneOffset);
                    endFullDay   = endFullDay.AddMinutes(-currentHotel.TimeZoneOffset);

                    // First Day
                    if (rangeDay.Start == this.rangeDay.Start)
                    {
                        // > OR >=
                        if (planDetail.UseEarlyCheckinFullDay.isUsed == true && rangeDay.Includes(startFullDay))
                        {
                            int hourFullDayEarlyCheckIn             = 0;
                            DateTime temp                           = rangeDay.Start.AddMinutes(currentHotel.TimeZoneOffset);
                            DateTime currentHotelFullDayCheckinDate = temp.Date + currentHotel.FullDayCheckinTime;
                            currentHotelFullDayCheckinDate          = currentHotelFullDayCheckinDate.AddMinutes(-currentHotel.TimeZoneOffset);
                            var numberOfMinuteFullDayEarlyCheckin   = (startFullDay - rangeDay.Start).TotalMinutes;

                            // > OR >=
                            if (numberOfMinuteFullDayEarlyCheckin > currentHotel.MinutesToRoundUp)
                            {
                                if (fullDayEarlyCheckInList.Count > 0)
                                {
                                    foreach (var fullDayEarlyCheckIn in fullDayEarlyCheckInList)
                                    {
                                        fullDayEarlyCheckIn.NumberOfHour = fullDayEarlyCheckIn.NumberOfHour * 60;
                                    }
                                    var flagEarlyCheckIn = 0;

                                    if (numberOfMinuteFullDayEarlyCheckin <= fullDayEarlyCheckInList[0].NumberOfHour)
                                    {
                                        hourFullDayEarlyCheckIn = (int)fullDayEarlyCheckInList[0].NumberOfHour / 60;
                                    }
                                    else if (numberOfMinuteFullDayEarlyCheckin < fullDayEarlyCheckInList[fullDayEarlyCheckInList.Count - 1].NumberOfHour && numberOfMinuteFullDayEarlyCheckin >= fullDayEarlyCheckInList[0].NumberOfHour)
                                    {
                                        for (int i = 1; i < fullDayEarlyCheckInList.Count; i++)
                                        {
                                            if (fullDayEarlyCheckInList[i].NumberOfHour > numberOfMinuteFullDayEarlyCheckin)
                                            {
                                                if (numberOfMinuteFullDayEarlyCheckin - fullDayEarlyCheckInList[i - 1].NumberOfHour > currentHotel.MinutesToRoundUp)
                                                {
                                                    flagEarlyCheckIn = i;
                                                    break;
                                                }
                                                else
                                                {
                                                    flagEarlyCheckIn = i - 1;
                                                    break;
                                                }
                                            }
                                        }
                                        hourFullDayEarlyCheckIn = (int)fullDayEarlyCheckInList[flagEarlyCheckIn].NumberOfHour / 60;
                                    }
                                    else if (numberOfMinuteFullDayEarlyCheckin == fullDayEarlyCheckInList[fullDayEarlyCheckInList.Count - 1].NumberOfHour)
                                    {
                                        hourFullDayEarlyCheckIn = (int)fullDayEarlyCheckInList[fullDayEarlyCheckInList.Count - 1].NumberOfHour / 60;
                                    }
                                    else if (numberOfMinuteFullDayEarlyCheckin > fullDayEarlyCheckInList[fullDayEarlyCheckInList.Count - 1].NumberOfHour)
                                    {
                                        if (numberOfMinuteFullDayEarlyCheckin > fullDayEarlyCheckInList[fullDayEarlyCheckInList.Count - 1].NumberOfHour + currentHotel.MinutesToRoundUp)
                                        {
                                            isFullDayEarlyCheckInToFullDay = true;
                                        }
                                        else
                                        {
                                            hourFullDayEarlyCheckIn = (int)fullDayEarlyCheckInList[fullDayEarlyCheckInList.Count - 1].NumberOfHour / 60;
                                        }
                                    }
                                }
                                else
                                {
                                    isFullDayEarlyCheckInToFullDay = true;
                                }

                                
                                if (!isFullDayEarlyCheckInToFullDay)
                                {
                                    var fullDayEarlyCheckin = planDetail.UseEarlyCheckinFullDay.adjustment.Find(adj => adj.NumberOfHour == hourFullDayEarlyCheckIn);
                                    if (fullDayEarlyCheckin != null)
                                    {
                                        valueAfterTempFullDay              = valueAfterTempFullDay + fullDayEarlyCheckin.Price;
                                        result.formula.FormulaEarlyCheckIn = new Dictionary<int, decimal>();
                                        result.formula.FormulaEarlyCheckIn.Add(hourFullDayEarlyCheckIn, fullDayEarlyCheckin.Price);
                                    }
                                    else
                                    {
                                        //Warning there are no early check in match
                                    }
                                }
                                // Số giờ CI sớm quá lớn, phạt thành 1 ngày
                                else
                                {
                                    valueAfterTempFullDay              = valueAfterTempFullDay + planDetail.UseFullDayPrice.price ?? 0.0M;
                                    result.formula.FormulaEarlyCheckIn = new Dictionary<int, decimal>();
                                    result.formula.FormulaEarlyCheckIn.Add(Int32.MaxValue, planDetail.UseFullDayPrice.price ?? 0.0M);
                                }
                            }
                        }
                        else
                        {
                            //Warning there are no early check in
                        }
                        
                    }//End of First Day
                    
                    // Last Day
                    if (rangeDay.End == this.rangeDay.End && rangeDay.Includes(endFullDay))
                    {
                        var fullDayLateCheckOutList = context.RoomPriceAdjustment.Where(rpa => rpa.HotelId == currentClientUser.HotelId && rpa.RoomPriceId == plan.RoomPriceId && rpa.AdjustmentCode == "OVERDUE_FULLDAY").OrderBy(o => o.NumberOfHour).ToList();
                        int hourFullDayLateCheckout = 0;
                        var numberOfMinuteFullDayLateCheckOut = 0.0;

                        DateTime temp                            = rangeDay.End.AddMinutes(currentHotel.TimeZoneOffset);
                        DateTime currentHotelFullDayCheckoutDate = temp.Date + currentHotel.FullDayCheckoutTime;
                        currentHotelFullDayCheckoutDate          = currentHotelFullDayCheckoutDate.AddMinutes(-currentHotel.TimeZoneOffset);
                        numberOfMinuteFullDayLateCheckOut        = (rangeDay.End - endFullDay).TotalMinutes;
                        if (numberOfMinuteFullDayLateCheckOut > currentHotel.MinutesToRoundUp)
                        {
                            if (fullDayLateCheckOutList != null && fullDayLateCheckOutList.Count == 0)
                            {
                                isFullDayLateCheckOutToFullDay = true;
                            }
                            else
                            {
                                foreach (var fullDayLateCheckOut in fullDayLateCheckOutList)
                                {
                                    fullDayLateCheckOut.NumberOfHour = fullDayLateCheckOut.NumberOfHour * 60;
                                }
                                var flagFullDayLateCheckOut = 0;
                                if (fullDayLateCheckOutList != null && fullDayLateCheckOutList.Count() > 0 && numberOfMinuteFullDayLateCheckOut <= fullDayLateCheckOutList[0].NumberOfHour)
                                {
                                    hourFullDayLateCheckout = (int)fullDayLateCheckOutList[0].NumberOfHour / 60;
                                }
                                else if (fullDayLateCheckOutList != null && fullDayLateCheckOutList.Count() > 0 && numberOfMinuteFullDayLateCheckOut < fullDayLateCheckOutList[fullDayLateCheckOutList.Count - 1].NumberOfHour && numberOfMinuteFullDayLateCheckOut > fullDayLateCheckOutList[0].NumberOfHour)
                                {
                                    for (int i = 1; i < fullDayLateCheckOutList.Count; i++)
                                    {
                                        if (fullDayLateCheckOutList[i].NumberOfHour > numberOfMinuteFullDayLateCheckOut)
                                        {
                                            if (numberOfMinuteFullDayLateCheckOut - fullDayLateCheckOutList[i - 1].NumberOfHour > currentHotel.MinutesToRoundUp)
                                            {
                                                flagFullDayLateCheckOut = i;
                                                break;
                                            }
                                            else
                                            {
                                                flagFullDayLateCheckOut = i - 1;
                                                break;
                                            }
                                        }
                                    }
                                    hourFullDayLateCheckout = (int)fullDayLateCheckOutList[flagFullDayLateCheckOut].NumberOfHour / 60;
                                }
                                else if (fullDayLateCheckOutList != null && fullDayLateCheckOutList.Count() > 0 && numberOfMinuteFullDayLateCheckOut == fullDayLateCheckOutList[fullDayLateCheckOutList.Count - 1].NumberOfHour)
                                {
                                    hourFullDayLateCheckout = (int)fullDayLateCheckOutList[fullDayLateCheckOutList.Count - 1].NumberOfHour / 60;
                                }
                                else if (fullDayLateCheckOutList != null && fullDayLateCheckOutList.Count() > 0 && numberOfMinuteFullDayLateCheckOut > fullDayLateCheckOutList[fullDayLateCheckOutList.Count - 1].NumberOfHour)
                                {
                                    if (numberOfMinuteFullDayLateCheckOut > fullDayLateCheckOutList[fullDayLateCheckOutList.Count - 1].NumberOfHour + currentHotel.MinutesToRoundUp)
                                    {
                                        isFullDayLateCheckOutToFullDay = true;
                                    }
                                    else
                                    {
                                        hourFullDayLateCheckout = (int)fullDayLateCheckOutList[fullDayLateCheckOutList.Count - 1].NumberOfHour / 60;
                                    }
                                }
                            }

                            if (!isFullDayLateCheckOutToFullDay)
                            {
                                var fullDayAdjustment = planDetail.UseFullDayPrice.adjustment.Find(adj => adj.NumberOfHour == hourFullDayLateCheckout);
                                if (fullDayAdjustment != null)
                                {
                                    if (result.formula.FormulaEarlyCheckIn != null)
                                    {
                                        if (this.totalHour * 60 > hotelTotalWorkTime)
                                        {
                                            valueAfterTempFullDay = valueAfterTempFullDay + fullDayAdjustment.Price;
                                            result.formula.FormulaLateCheckOut = new Dictionary<int, decimal>();
                                            result.formula.FormulaLateCheckOut.Add(hourFullDayLateCheckout, fullDayAdjustment.Price);
                                        }
                                    }
                                    else
                                    {
                                        valueAfterTempFullDay = valueAfterTempFullDay + fullDayAdjustment.Price;
                                        result.formula.FormulaLateCheckOut = new Dictionary<int, decimal>();
                                        result.formula.FormulaLateCheckOut.Add(hourFullDayLateCheckout, fullDayAdjustment.Price);
                                    }

                                }
                                else
                                {
                                    //Warning there are no full day late check out match
                                }
                            }
                            else
                            {
                                if (result.formula.FormulaEarlyCheckIn != null)
                                {
                                    if (this.totalHour * 60 > hotelTotalWorkTime)
                                    {
                                        valueAfterTempFullDay = valueAfterTempFullDay + planDetail.UseFullDayPrice.price ?? 0.0M;
                                        result.formula.FormulaLateCheckOut = new Dictionary<int, decimal>();
                                        result.formula.FormulaLateCheckOut.Add(Int32.MaxValue, planDetail.UseFullDayPrice.price ?? 0.0M);
                                    }
                                }
                                else
                                {
                                    valueAfterTempFullDay = valueAfterTempFullDay + planDetail.UseFullDayPrice.price ?? 0.0M;
                                    result.formula.FormulaLateCheckOut = new Dictionary<int, decimal>();
                                    result.formula.FormulaLateCheckOut.Add(Int32.MaxValue, planDetail.UseFullDayPrice.price ?? 0.0M);
                                }
                            }
                        }
                    }
                    //This Range Day Price
                    valueAfterTempFullDay     = valueAfterTempFullDay + planDetail.UseFullDayPrice.price ?? 0.0M;
                    result.formula.ValueAfter = valueAfterTempFullDay;
                }
            }
            return result;
        }
        

        public PlanListHourlyFormula CalculateRangeHourInPlan(PlanViewModel plan, DateRange rangeHour)
        {
            PlanListHourlyFormula result = new PlanListHourlyFormula();
            int minutes = (int)(rangeHour.End - rangeHour.Start).TotalMinutes;
            int hours = (int)(rangeHour.End - rangeHour.Start).TotalHours;

            // > OR >=
            if (minutes >= currentHotel.MinutesToRoundUp)
            {
                PlanDetailViewModel planDetail = null;
                for (int i = 0; i < this.model.currentRoomType.planDetailList.Count; i++)
                {
                    if (this.model.currentRoomType.planDetailList[i].Plan.RoomPriceId == plan.RoomPriceId)
                    {
                        planDetail = this.model.currentRoomType.planDetailList[i];
                        break;
                    }
                }

                PlanListConstantlyFormula hourRemainByHourlyPriceFormula   = new PlanListConstantlyFormula();
                hourRemainByHourlyPriceFormula.ValueAfter                  = Decimal.MaxValue;
                PlanListConstantlyFormula hourRemainByFullDayPriceFormula  = new PlanListConstantlyFormula(plan, "FULL_DAY_PRICE", rangeHour, 4, "HOUR(S)", totalPrice, planDetail.UseFullDayPrice.price ?? 0.0M, hour);
                hourRemainByFullDayPriceFormula.ValueAfter                 = Decimal.MaxValue;
                PlanListConstantlyFormula hourRemainByDayNightPriceFormula = new PlanListConstantlyFormula(plan, "DAY_NIGHT_PRICE", rangeHour, 4, "HOUR(S)", totalPrice, planDetail.UseDayNightPrice.price ?? 0.0M, hour);
                hourRemainByDayNightPriceFormula.ValueAfter                = Decimal.MaxValue;

                if (planDetail.UseHourlyPrice.isUsed == true)
                {
                    var valueAfterTemp = this.totalPrice;
                    List<RoomPriceAdjustment> hourlyPriceList = context.RoomPriceAdjustment.Where(rpa => rpa.HotelId == currentClientUser.HotelId && rpa.RoomPriceId == plan.RoomPriceId && rpa.AdjustmentCode == "HOURLY_PRICE").ToList();
                    if (hourlyPriceList.Count > 0)
                    {
                        hourlyPriceList = hourlyPriceList.OrderBy(o => o.NumberOfHour).ToList();
                        var hourlyPriceListTemp = hourlyPriceList;
                        foreach (var hourlyPrice in hourlyPriceList)
                        {
                            hourlyPrice.NumberOfHour = hourlyPrice.NumberOfHour * 60;
                        }
                        var index = 0;
                        if (minutes == currentHotel.MinutesToRoundUp)
                        {
                            hour = 1;
                        }
                        else if (minutes <= hourlyPriceList[0].NumberOfHour)
                        {
                            hour = (int)hourlyPriceList[0].NumberOfHour / 60;
                        }
                        else if (minutes < hourlyPriceList[hourlyPriceListTemp.Count - 1].NumberOfHour && minutes > hourlyPriceList[0].NumberOfHour)
                        {
                            for (int i = 1; i < hourlyPriceList.Count; i++)
                            {
                                if (hourlyPriceList[i].NumberOfHour >= minutes)
                                {
                                    if (minutes - hourlyPriceList[i - 1].NumberOfHour >= currentHotel.MinutesToRoundUp)
                                    {
                                        index = i;
                                        break;
                                    }
                                    else
                                    {
                                        index = i - 1;
                                        break;
                                    }
                                }
                            }
                            hour = (int)hourlyPriceList[index].NumberOfHour / 60;
                        }
                        else if (minutes == hourlyPriceList[hourlyPriceListTemp.Count - 1].NumberOfHour)
                        {
                            hour = (int)hourlyPriceList[hourlyPriceListTemp.Count - 1].NumberOfHour / 60;
                        }

                        var hourlyPriceAdjustment = planDetail.UseHourlyPrice.adjustment.Find(adj => adj.NumberOfHour == hour);
                        if (hourlyPriceAdjustment != null)
                        {
                            hourRemainByHourlyPriceFormula = new PlanListConstantlyFormula(plan, "HOURLY_PRICE", rangeHour, 4, "HOUR(S)", totalPrice, hourlyPriceAdjustment.Price, hour);
                            hourRemainByHourlyPriceFormula.ValueAfter = totalPrice + hourlyPriceAdjustment.Price;
                            //result.availableHourlyFormula = new List<PlanListConstantlyFormula>();
                            if (result.availableHourlyFormula == null || result.availableHourlyFormula.Count == 0)
                            {
                                result.availableHourlyFormula = new List<PlanListConstantlyFormula>();
                            }
                            result.availableHourlyFormula.Add(hourRemainByHourlyPriceFormula);
                        }
                        else
                        {
                            //Warning there is no hourly price match
                        }
                    }//hourlyPriceList.Count > 0
                    else
                    {
                        //Warning there is no hourly price
                    }
                }

                if (planDetail.UseFullDayPrice.isUsed == true)
                {
                    var valueAfterTempFullDay           = this.totalPrice;
                    bool isFullDayEarlyCheckInToFullDay = false;
                    bool isFullDayLateCheckOutToFullDay = false;

                    TimeSpan checkInTime  = currentHotel.FullDayCheckinTime;
                    TimeSpan checkOutTime = currentHotel.FullDayCheckoutTime;
                    DateTime startFullDay = rangeHour.Start.AddMinutes(currentHotel.TimeZoneOffset).Date + checkInTime;
                    DateTime endFullDay   = rangeHour.End.AddMinutes(currentHotel.TimeZoneOffset).Date + checkOutTime;

                    startFullDay = startFullDay.AddMinutes(-currentHotel.TimeZoneOffset);
                    endFullDay   = endFullDay.AddMinutes(-currentHotel.TimeZoneOffset);
                    if (startFullDay.Date != endFullDay.Date)
                    {
                        if (rangeHour.Start <= startFullDay && rangeHour.End <= endFullDay)
                        {
                            endFullDay = startFullDay;
                        }
                        else if (startFullDay <= rangeHour.Start && rangeHour.End <= endFullDay)
                        {
                            startFullDay = endFullDay;
                        }
                        else if (startFullDay <= rangeHour.Start && rangeHour.Start <= endFullDay && endFullDay <= rangeHour.End)
                        {
                            startFullDay = endFullDay;
                        }
                    }

                    //If calculating full day in case <=24 hour, get the min value of
                    var valueAfterCase1           = planDetail.UseFullDayPrice.price ?? 0.0M;
                    var valueAfterCase2           = planDetail.UseFullDayPrice.price ?? 0.0M;
                    var case1_FormulaEarlyCheckIn = new Dictionary<int, decimal>();
                    var case2_FormulaEarlyCheckIn = new Dictionary<int, decimal>();
                    var case1_FormulaLateCheckOut = new Dictionary<int, decimal>();
                    var case2_FormulaLateCheckOut = new Dictionary<int, decimal>();

                    //Case 1: Full Day + Late Check Out
                    if (rangeHour != null)
                    {
                        List<RoomPriceAdjustment> fullDayLateCheckOutList = context.RoomPriceAdjustment.Where(rpa => rpa.HotelId == currentClientUser.HotelId && rpa.RoomPriceId == plan.RoomPriceId && rpa.AdjustmentCode == "OVERDUE_FULLDAY").ToList();
                        int hourFullDayLateCheckout = 0;
                        DateTime temp = rangeHour.End.AddMinutes(currentHotel.TimeZoneOffset);
                        DateTime currentHotelFullDayCheckoutDate = temp.Date + currentHotel.FullDayCheckoutTime;
                        currentHotelFullDayCheckoutDate = currentHotelFullDayCheckoutDate.AddMinutes(-currentHotel.TimeZoneOffset);
                        var numberOfMinuteFullDayLateCheckOut = (rangeHour.End - endFullDay).TotalMinutes;
                        if (numberOfMinuteFullDayLateCheckOut > currentHotel.MinutesToRoundUp)
                        {
                            if (fullDayLateCheckOutList.Count == 0)
                            {
                                isFullDayLateCheckOutToFullDay = true;
                            }
                            else
                            {
                                fullDayLateCheckOutList = fullDayLateCheckOutList.OrderBy(o => o.NumberOfHour).ToList();
                                foreach (var fullDayLateCheckOut in fullDayLateCheckOutList)
                                {
                                    fullDayLateCheckOut.NumberOfHour = fullDayLateCheckOut.NumberOfHour * 60;
                                }
                                var flagFullDayLateCheckOut = 0;

                                if (fullDayLateCheckOutList != null && fullDayLateCheckOutList.Count() > 0 && numberOfMinuteFullDayLateCheckOut <= fullDayLateCheckOutList[0].NumberOfHour)
                                {
                                    hourFullDayLateCheckout = (int)fullDayLateCheckOutList[0].NumberOfHour / 60;
                                }
                                else if (fullDayLateCheckOutList != null && fullDayLateCheckOutList.Count() > 0 && numberOfMinuteFullDayLateCheckOut < fullDayLateCheckOutList[fullDayLateCheckOutList.Count - 1].NumberOfHour && numberOfMinuteFullDayLateCheckOut > fullDayLateCheckOutList[0].NumberOfHour)
                                {
                                    for (int i = 1; i < fullDayLateCheckOutList.Count; i++)
                                    {
                                        if (fullDayLateCheckOutList[i].NumberOfHour > numberOfMinuteFullDayLateCheckOut)
                                        {
                                            if (numberOfMinuteFullDayLateCheckOut - fullDayLateCheckOutList[i - 1].NumberOfHour > currentHotel.MinutesToRoundUp)
                                            {
                                                flagFullDayLateCheckOut = i;
                                                break;
                                            }
                                            else
                                            {
                                                flagFullDayLateCheckOut = i - 1;
                                                break;
                                            }
                                        }
                                    }
                                    hourFullDayLateCheckout = (int)fullDayLateCheckOutList[flagFullDayLateCheckOut].NumberOfHour / 60;
                                }
                                else if (fullDayLateCheckOutList != null && fullDayLateCheckOutList.Count() > 0 && numberOfMinuteFullDayLateCheckOut == fullDayLateCheckOutList[fullDayLateCheckOutList.Count - 1].NumberOfHour)
                                {
                                    hourFullDayLateCheckout = (int)fullDayLateCheckOutList[fullDayLateCheckOutList.Count - 1].NumberOfHour / 60;
                                }
                                else if (numberOfMinuteFullDayLateCheckOut > fullDayLateCheckOutList[fullDayLateCheckOutList.Count - 1].NumberOfHour)
                                {
                                    if (numberOfMinuteFullDayLateCheckOut > fullDayLateCheckOutList[fullDayLateCheckOutList.Count - 1].NumberOfHour + currentHotel.MinutesToRoundUp)
                                    {
                                        isFullDayLateCheckOutToFullDay = true;
                                    }
                                    else
                                    {
                                        hourFullDayLateCheckout = (int)fullDayLateCheckOutList[fullDayLateCheckOutList.Count - 1].NumberOfHour / 60;
                                    }
                                }
                            }

                            if (!isFullDayLateCheckOutToFullDay)
                            {
                                var fullDayAdjustment = planDetail.UseFullDayPrice.adjustment.Find(adj => adj.NumberOfHour == hourFullDayLateCheckout);
                                if (fullDayAdjustment != null)
                                {
                                    valueAfterCase1 = valueAfterCase1 + fullDayAdjustment.Price;
                                    case1_FormulaLateCheckOut.Add(hourFullDayLateCheckout, fullDayAdjustment.Price);
                                }
                                else
                                {
                                    //Warning there are no full day late check out match
                                }
                            }
                            else
                            {
                                valueAfterCase1 = valueAfterCase1 + planDetail.UseFullDayPrice.price ?? 0.0M;
                                case1_FormulaLateCheckOut.Add(Int32.MaxValue, planDetail.UseFullDayPrice.price ?? 0.0M);
                            }
                        }

                        else
                        {
                            //Warning there are no full day late check out
                        }
                    }// End Case 1

                    //Case 2: Early Check + Full Day
                    // Range Hour Must Be Include Current Hotel FullDayCheckoutTime
                    if (rangeHour != null)
                    {
                        if (planDetail.UseEarlyCheckinFullDay.isUsed == true)
                        {
                            List<RoomPriceAdjustment> fullDayEarlyCheckInList = context.RoomPriceAdjustment.Where(rpa => rpa.HotelId == currentClientUser.HotelId && rpa.RoomPriceId == plan.RoomPriceId && rpa.AdjustmentCode == "EARLY_CHECKIN_FULL_DAY").ToList();
                            int hourFullDayEarlyCheckIn = 0;
                            DateTime startTemp = rangeHour.Start.AddMinutes(currentHotel.TimeZoneOffset);
                            DateTime currentHotelFullDayCheckinDate = startTemp.Date + currentHotel.FullDayCheckinTime;
                            currentHotelFullDayCheckinDate = currentHotelFullDayCheckinDate.AddMinutes(-currentHotel.TimeZoneOffset);
                            var numberOfMinuteFullDayEarlyCheckin = (startFullDay - rangeHour.Start).TotalMinutes;
                            if (numberOfMinuteFullDayEarlyCheckin > currentHotel.MinutesToRoundUp)
                            {
                                if (fullDayEarlyCheckInList.Count > 0)
                                {
                                    fullDayEarlyCheckInList = fullDayEarlyCheckInList.OrderBy(o => o.NumberOfHour).ToList();
                                    foreach (var fullDayEarlyCheckIn in fullDayEarlyCheckInList)
                                    {
                                        fullDayEarlyCheckIn.NumberOfHour = fullDayEarlyCheckIn.NumberOfHour * 60;
                                    }
                                    var flagEarlyCheckIn = 0;

                                    if (numberOfMinuteFullDayEarlyCheckin <= fullDayEarlyCheckInList[0].NumberOfHour)
                                    {
                                        hourFullDayEarlyCheckIn = (int)fullDayEarlyCheckInList[0].NumberOfHour / 60;
                                    }
                                    else if (numberOfMinuteFullDayEarlyCheckin < fullDayEarlyCheckInList[fullDayEarlyCheckInList.Count - 1].NumberOfHour && numberOfMinuteFullDayEarlyCheckin >= fullDayEarlyCheckInList[0].NumberOfHour)
                                    {
                                        for (int i = 1; i < fullDayEarlyCheckInList.Count; i++)
                                        {
                                            if (fullDayEarlyCheckInList[i].NumberOfHour > numberOfMinuteFullDayEarlyCheckin)
                                            {
                                                if (numberOfMinuteFullDayEarlyCheckin - fullDayEarlyCheckInList[i - 1].NumberOfHour > currentHotel.MinutesToRoundUp)
                                                {
                                                    flagEarlyCheckIn = i;
                                                    break;
                                                }
                                                else
                                                {
                                                    flagEarlyCheckIn = i - 1;
                                                    break;
                                                }
                                            }
                                        }
                                        hourFullDayEarlyCheckIn = (int)fullDayEarlyCheckInList[flagEarlyCheckIn].NumberOfHour / 60;
                                    }
                                    else if (numberOfMinuteFullDayEarlyCheckin == fullDayEarlyCheckInList[fullDayEarlyCheckInList.Count - 1].NumberOfHour)
                                    {
                                        hourFullDayEarlyCheckIn = (int)fullDayEarlyCheckInList[fullDayEarlyCheckInList.Count - 1].NumberOfHour / 60;
                                    }
                                    else if (numberOfMinuteFullDayEarlyCheckin > fullDayEarlyCheckInList[fullDayEarlyCheckInList.Count - 1].NumberOfHour)
                                    {
                                        if (numberOfMinuteFullDayEarlyCheckin > fullDayEarlyCheckInList[fullDayEarlyCheckInList.Count - 1].NumberOfHour + currentHotel.MinutesToRoundUp)
                                        {
                                            isFullDayEarlyCheckInToFullDay = true;
                                        }
                                        else
                                        {
                                            hourFullDayEarlyCheckIn = (int)fullDayEarlyCheckInList[fullDayEarlyCheckInList.Count - 1].NumberOfHour / 60;
                                        }
                                    }
                                }
                                else
                                {
                                    isFullDayEarlyCheckInToFullDay = true;
                                }

                                if (!isFullDayEarlyCheckInToFullDay)
                                {
                                    var fullDayEarlyCheckin = planDetail.UseEarlyCheckinFullDay.adjustment.Find(adj => adj.NumberOfHour == hourFullDayEarlyCheckIn);
                                    if (fullDayEarlyCheckin != null)
                                    {
                                        valueAfterCase2 = valueAfterCase2 + fullDayEarlyCheckin.Price;
                                        case2_FormulaEarlyCheckIn.Add(hourFullDayEarlyCheckIn, fullDayEarlyCheckin.Price);
                                    }
                                    else
                                    {
                                        //Warning there are no early check in match
                                    }
                                }
                                else
                                {
                                    valueAfterCase2 = valueAfterCase2 + planDetail.UseFullDayPrice.price ?? 0.0M;
                                    case2_FormulaEarlyCheckIn.Add(Int32.MaxValue, planDetail.UseFullDayPrice.price ?? 0.0M);
                                }
                            }
                        }//UseEarlyCheckIn
                        else
                        {
                            //Warning there are no early check in
                        }
                    }//End Include Early Checkin

                    if (case2_FormulaEarlyCheckIn == null && rangeHour != null)
                    {
                        var fullDayLateCheckOutList = context.RoomPriceAdjustment.Where(rpa => rpa.HotelId == currentClientUser.HotelId && rpa.RoomPriceId == plan.RoomPriceId && rpa.AdjustmentCode == "OVERDUE_FULLDAY").ToList();
                        int hourFullDayLateCheckout = 0;
                        DateTime temp = rangeHour.End.AddMinutes(currentHotel.TimeZoneOffset);
                        DateTime currentHotelFullDayCheckoutDate = temp.Date + currentHotel.FullDayCheckoutTime;
                        currentHotelFullDayCheckoutDate = currentHotelFullDayCheckoutDate.AddMinutes(-currentHotel.TimeZoneOffset);
                        var numberOfMinuteFullDayLateCheckOut = (rangeHour.End - endFullDay).TotalMinutes;
                        if (numberOfMinuteFullDayLateCheckOut > currentHotel.MinutesToRoundUp)
                        {
                            if (fullDayLateCheckOutList.Count == 0)
                            {
                                isFullDayLateCheckOutToFullDay = true;
                            }
                            else
                            {
                                fullDayLateCheckOutList = fullDayLateCheckOutList.OrderBy(o => o.NumberOfHour).ToList();
                                foreach (var fullDayLateCheckOut in fullDayLateCheckOutList)
                                {
                                    fullDayLateCheckOut.NumberOfHour = fullDayLateCheckOut.NumberOfHour * 60;
                                }
                                var flagFullDayLateCheckOut = 0;

                                if (fullDayLateCheckOutList != null && fullDayLateCheckOutList.Count() > 0 && numberOfMinuteFullDayLateCheckOut <= fullDayLateCheckOutList[0].NumberOfHour)
                                {
                                    hourFullDayLateCheckout = (int)fullDayLateCheckOutList[0].NumberOfHour / 60;
                                }
                                else if (fullDayLateCheckOutList != null && fullDayLateCheckOutList.Count() > 0 && numberOfMinuteFullDayLateCheckOut < fullDayLateCheckOutList[fullDayLateCheckOutList.Count - 1].NumberOfHour && numberOfMinuteFullDayLateCheckOut > fullDayLateCheckOutList[0].NumberOfHour)
                                {
                                    for (int i = 1; i < fullDayLateCheckOutList.Count; i++)
                                    {
                                        if (fullDayLateCheckOutList[i].NumberOfHour > numberOfMinuteFullDayLateCheckOut)
                                        {
                                            if (numberOfMinuteFullDayLateCheckOut - fullDayLateCheckOutList[i - 1].NumberOfHour > currentHotel.MinutesToRoundUp)
                                            {
                                                flagFullDayLateCheckOut = i;
                                                break;
                                            }
                                            else
                                            {
                                                flagFullDayLateCheckOut = i - 1;
                                                break;
                                            }
                                        }
                                    }
                                    hourFullDayLateCheckout = (int)fullDayLateCheckOutList[flagFullDayLateCheckOut].NumberOfHour / 60;
                                }
                                else if (fullDayLateCheckOutList != null && fullDayLateCheckOutList.Count() > 0 && numberOfMinuteFullDayLateCheckOut == fullDayLateCheckOutList[fullDayLateCheckOutList.Count - 1].NumberOfHour)
                                {
                                    hourFullDayLateCheckout = (int)fullDayLateCheckOutList[fullDayLateCheckOutList.Count - 1].NumberOfHour / 60;
                                }
                                else if (numberOfMinuteFullDayLateCheckOut > fullDayLateCheckOutList[fullDayLateCheckOutList.Count - 1].NumberOfHour)
                                {
                                    if (numberOfMinuteFullDayLateCheckOut > fullDayLateCheckOutList[fullDayLateCheckOutList.Count - 1].NumberOfHour + currentHotel.MinutesToRoundUp)
                                    {
                                        isFullDayLateCheckOutToFullDay = true;
                                    }
                                    else
                                    {
                                        hourFullDayLateCheckout = (int)fullDayLateCheckOutList[fullDayLateCheckOutList.Count - 1].NumberOfHour / 60;
                                    }
                                }
                            }

                            if (!isFullDayLateCheckOutToFullDay)
                            {
                                var fullDayAdjustment = planDetail.UseFullDayPrice.adjustment.Find(adj => adj.NumberOfHour == hourFullDayLateCheckout);
                                if (fullDayAdjustment != null)
                                {
                                    valueAfterCase2 = valueAfterCase2 + fullDayAdjustment.Price;
                                    case2_FormulaEarlyCheckIn.Add(hourFullDayLateCheckout, fullDayAdjustment.Price);
                                }
                                else
                                {
                                    //Warning there are no full day late check out match
                                }
                            }
                            else
                            {
                                valueAfterCase2 = valueAfterCase2 + planDetail.UseFullDayPrice.price ?? 0.0M;
                                case2_FormulaEarlyCheckIn.Add(Int32.MaxValue, planDetail.UseFullDayPrice.price ?? 0.0M);
                            }
                        }

                        //}//fullDayLateCheckOut.Count > 0
                        else
                        {
                            //Warning there are no full day late check out
                        }
                    }
                    //End Case 2

                    // Get The Min Value of 2 cases
                    decimal minValue = Math.Min(valueAfterCase1, valueAfterCase2);
                    if (minValue == valueAfterCase2)
                    {
                        valueAfterTempFullDay = valueAfterCase2;
                        hourRemainByFullDayPriceFormula.ValueAfter = valueAfterTempFullDay;
                        hourRemainByFullDayPriceFormula.FormulaEarlyCheckIn = case2_FormulaEarlyCheckIn;
                        hourRemainByFullDayPriceFormula.FormulaLateCheckOut = case2_FormulaLateCheckOut;
                    }
                    else
                    {
                        valueAfterTempFullDay = valueAfterCase1;
                        hourRemainByFullDayPriceFormula.ValueAfter = valueAfterTempFullDay;
                        hourRemainByFullDayPriceFormula.FormulaEarlyCheckIn = case1_FormulaEarlyCheckIn;
                        hourRemainByFullDayPriceFormula.FormulaLateCheckOut = case1_FormulaLateCheckOut;
                    }

                    if (result.availableHourlyFormula == null || result.availableHourlyFormula.Count == 0)
                    {
                        result.availableHourlyFormula = new List<PlanListConstantlyFormula>();
                    }
                    result.availableHourlyFormula.Add(hourRemainByFullDayPriceFormula);
                }

                if (planDetail.UseDayNightPrice.isUsed == true)
                {
                    var valueAfterTempDayNight           = this.totalPrice;
                    bool isDayNightEarlyCheckInToFullDay = false;
                    bool isDayNightLateCheckOutToFullDay = false;
                    TimeSpan startTime                   = currentHotel.DayNightStartTime ?? default(TimeSpan);
                    TimeSpan endTime                     = currentHotel.DayNightEndTime ?? default(TimeSpan);
                    var startTemp                        = rangeHour.Start.AddMinutes(currentHotel.TimeZoneOffset);
                    var endTemp                          = rangeHour.End.AddMinutes(currentHotel.TimeZoneOffset);
                    var start                            = startTemp.Date.Add(startTime);
                    var end                              = startTemp.Date.Add(endTime);
                    if (start <= end)
                    {
                        // <= 1 ngay khong lam gi ca (Khung gio qua dem cung 1 ngay)
                    }
                    else
                    {
                        //var startTemp = rangeHour.Start.AddHours(currentHotel.TimeZoneOffset / 60).Hour;
                        var hourTemp = startTemp.Hour;
                        if (hourTemp < 12)
                        {
                            if (startTemp.Date == endTemp.Date && startTemp < endTemp)
                            {
                                start = start.AddDays(-1);
                            }
                        }
                        else
                        {
                            end = end.AddDays(1);
                        }
                    }

                    start = start.AddMinutes(-currentHotel.TimeZoneOffset);
                    end = end.AddMinutes(-currentHotel.TimeZoneOffset);
                    //Range Hour Must Be in DayNight Time Range
                    if ((rangeHour.Start <= start && start <= rangeHour.End) || (start <= rangeHour.Start && rangeHour.End <= end) || (rangeHour.Start <= end && end <= rangeHour.End) || (rangeHour.Start <= start && end <= rangeHour.End))
                    {
                        // Early check in must be includes DayNight start
                        //if (rangeHourTemp.Start.TimeOfDay <= currentHotel.FullDayCheckoutTime && currentHotel.FullDayCheckoutTime <= rangeHourTemp.End.TimeOfDay)
                        if (rangeHour.Includes(start))
                        {
                            if (planDetail.UseEarlyCheckinDayNight.isUsed == true)
                            {
                                List<RoomPriceAdjustment> dayNightEarlyCheckInList = context.RoomPriceAdjustment.Where(rpa => rpa.HotelId == currentClientUser.HotelId && rpa.RoomPriceId == plan.RoomPriceId && rpa.AdjustmentCode == "EARLY_CHECKIN_DAY_NIGHT").ToList();
                                int hourDayNightEarlyCheckIn = 0;
                                TimeSpan dayNightStartTime = currentHotel.DayNightStartTime ?? default(TimeSpan);
                                var temp = rangeHour.Start.AddMinutes(currentHotel.TimeZoneOffset);
                                var currentHotelDayNightStartDate = temp.Date + dayNightStartTime;
                                currentHotelDayNightStartDate = currentHotelDayNightStartDate.AddMinutes(-currentHotel.TimeZoneOffset);
                                var numberOfMinuteDayNightEarlyCheckin = (currentHotelDayNightStartDate - rangeHour.Start).TotalMinutes;
                                if (dayNightEarlyCheckInList.Count > 0)
                                {
                                    if (numberOfMinuteDayNightEarlyCheckin > currentHotel.MinutesToRoundUp)
                                    {
                                        dayNightEarlyCheckInList = dayNightEarlyCheckInList.OrderBy(o => o.NumberOfHour).ToList();
                                        foreach (var dayNightEarlyCheckIn in dayNightEarlyCheckInList)
                                        {
                                            dayNightEarlyCheckIn.NumberOfHour = dayNightEarlyCheckIn.NumberOfHour * 60;
                                        }
                                        var flagEarlyCheckIn = 0;
                                        if (numberOfMinuteDayNightEarlyCheckin <= dayNightEarlyCheckInList[0].NumberOfHour)
                                        {
                                            hourDayNightEarlyCheckIn = (int)dayNightEarlyCheckInList[0].NumberOfHour / 60;
                                        }
                                        else if (numberOfMinuteDayNightEarlyCheckin < dayNightEarlyCheckInList[dayNightEarlyCheckInList.Count - 1].NumberOfHour && numberOfMinuteDayNightEarlyCheckin > dayNightEarlyCheckInList[0].NumberOfHour)
                                        {
                                            for (int i = 1; i < dayNightEarlyCheckInList.Count; i++)
                                            {
                                                if (dayNightEarlyCheckInList[i].NumberOfHour > numberOfMinuteDayNightEarlyCheckin)
                                                {
                                                    if (numberOfMinuteDayNightEarlyCheckin - dayNightEarlyCheckInList[i - 1].NumberOfHour > currentHotel.MinutesToRoundUp)
                                                    {
                                                        flagEarlyCheckIn = i;
                                                        break;
                                                    }
                                                    else
                                                    {
                                                        flagEarlyCheckIn = i - 1;
                                                        break;
                                                    }
                                                }
                                            }
                                            hourDayNightEarlyCheckIn = (int)dayNightEarlyCheckInList[flagEarlyCheckIn].NumberOfHour / 60;
                                        }
                                        else if (numberOfMinuteDayNightEarlyCheckin == dayNightEarlyCheckInList[dayNightEarlyCheckInList.Count - 1].NumberOfHour)
                                        {
                                            hourDayNightEarlyCheckIn = (int)dayNightEarlyCheckInList[dayNightEarlyCheckInList.Count - 1].NumberOfHour / 60;
                                        }
                                        else if (numberOfMinuteDayNightEarlyCheckin > dayNightEarlyCheckInList[dayNightEarlyCheckInList.Count - 1].NumberOfHour)
                                        {
                                            if (numberOfMinuteDayNightEarlyCheckin > dayNightEarlyCheckInList[dayNightEarlyCheckInList.Count - 1].NumberOfHour + currentHotel.MinutesToRoundUp)
                                            {
                                                isDayNightEarlyCheckInToFullDay = true;
                                            }
                                            else
                                            {
                                                hourDayNightEarlyCheckIn = (int)dayNightEarlyCheckInList[dayNightEarlyCheckInList.Count - 1].NumberOfHour / 60;
                                            }
                                        }
                                        if (!isDayNightEarlyCheckInToFullDay)
                                        {
                                            var dayNightEarlyCheckin = planDetail.UseEarlyCheckinDayNight.adjustment.Find(adj => adj.NumberOfHour == hourDayNightEarlyCheckIn);
                                            if (dayNightEarlyCheckin != null)
                                            {
                                                valueAfterTempDayNight = valueAfterTempDayNight + dayNightEarlyCheckin.Price;
                                                hourRemainByDayNightPriceFormula.FormulaEarlyCheckIn = new Dictionary<int, decimal>();
                                                hourRemainByDayNightPriceFormula.FormulaEarlyCheckIn.Add(hourDayNightEarlyCheckIn, dayNightEarlyCheckin.Price);
                                            }
                                            else
                                            {
                                                //Warning there are no day night early check in match
                                            }
                                        }
                                        else
                                        {
                                            valueAfterTempDayNight = valueAfterTempDayNight + planDetail.UseDayNightPrice.price ?? 0.0M;
                                            hourRemainByDayNightPriceFormula.FormulaEarlyCheckIn = new Dictionary<int, decimal>();
                                            hourRemainByDayNightPriceFormula.FormulaEarlyCheckIn.Add(Int32.MaxValue, planDetail.UseDayNightPrice.price ?? 0.0M);
                                        }
                                    }
                                }//dayNightEarlyCheckInList.Count > 0
                                else
                                {
                                    //Warning there are no day night early check in
                                    
                                    //Phat 1 ngay dem
                                    valueAfterTempDayNight = valueAfterTempDayNight + planDetail.UseDayNightPrice.price ?? 0.0M;
                                    hourRemainByDayNightPriceFormula.FormulaEarlyCheckIn = new Dictionary<int, decimal>();
                                    hourRemainByDayNightPriceFormula.FormulaEarlyCheckIn.Add(Int32.MaxValue, planDetail.UseDayNightPrice.price ?? 0.0M);
                                    

                                }
                                
                            }
                        }

                        // Late check out must be includes DayNight end
                        if (rangeHour.Includes(end))
                        {
                            List<RoomPriceAdjustment> dayNightLateCheckOutList = context.RoomPriceAdjustment.Where(rpa => rpa.HotelId == currentClientUser.HotelId && rpa.RoomPriceId == plan.RoomPriceId && rpa.AdjustmentCode == "OVERDUE_DAYNIGHT").ToList();
                            TimeSpan dayNightCheckOutTime = currentHotel.DayNightEndTime ?? default(TimeSpan);

                            int hourDayNightLateCheckout = 0;
                            DateTime temp = rangeHour.End.AddMinutes(currentHotel.TimeZoneOffset);
                            DateTime currentHotelDayNightCheckoutDate = temp.Date + dayNightCheckOutTime;
                            currentHotelDayNightCheckoutDate = currentHotelDayNightCheckoutDate.AddMinutes(-currentHotel.TimeZoneOffset);
                            var numberOfMinuteDayNightLateCheckOut = (rangeHour.End - currentHotelDayNightCheckoutDate).TotalMinutes;
                            if (numberOfMinuteDayNightLateCheckOut > currentHotel.MinutesToRoundUp)
                            {
                                if (dayNightLateCheckOutList.Count == 0)
                                {
                                    isDayNightLateCheckOutToFullDay = true;
                                }
                                else
                                {
                                    dayNightLateCheckOutList = dayNightLateCheckOutList.OrderBy(o => o.NumberOfHour).ToList();
                                    foreach (var dayNightLateCheckOut in dayNightLateCheckOutList)
                                    {
                                        dayNightLateCheckOut.NumberOfHour = dayNightLateCheckOut.NumberOfHour * 60;
                                    }
                                    var flagDayNightLateCheckOut = 0;

                                    if (numberOfMinuteDayNightLateCheckOut <= dayNightLateCheckOutList[0].NumberOfHour)
                                    {
                                        hourDayNightLateCheckout = (int)dayNightLateCheckOutList[0].NumberOfHour / 60;
                                    }
                                    else if (numberOfMinuteDayNightLateCheckOut < dayNightLateCheckOutList[dayNightLateCheckOutList.Count - 1].NumberOfHour && numberOfMinuteDayNightLateCheckOut > dayNightLateCheckOutList[0].NumberOfHour)
                                    {
                                        for (int i = 1; i < dayNightLateCheckOutList.Count; i++)
                                        {
                                            if (dayNightLateCheckOutList[i].NumberOfHour > numberOfMinuteDayNightLateCheckOut)
                                            {
                                                if (numberOfMinuteDayNightLateCheckOut - dayNightLateCheckOutList[i - 1].NumberOfHour > currentHotel.MinutesToRoundUp)
                                                {
                                                    flagDayNightLateCheckOut = i;
                                                    break;
                                                }
                                                else
                                                {
                                                    flagDayNightLateCheckOut = i - 1;
                                                    break;
                                                }
                                            }
                                        }
                                        hourDayNightLateCheckout = (int)dayNightLateCheckOutList[flagDayNightLateCheckOut].NumberOfHour / 60;
                                    }
                                    else if (numberOfMinuteDayNightLateCheckOut == dayNightLateCheckOutList[dayNightLateCheckOutList.Count - 1].NumberOfHour)
                                    {
                                        hourDayNightLateCheckout = (int)dayNightLateCheckOutList[dayNightLateCheckOutList.Count - 1].NumberOfHour / 60;
                                    }
                                    else if (numberOfMinuteDayNightLateCheckOut > dayNightLateCheckOutList[dayNightLateCheckOutList.Count - 1].NumberOfHour)
                                    {
                                        if (numberOfMinuteDayNightLateCheckOut > dayNightLateCheckOutList[dayNightLateCheckOutList.Count - 1].NumberOfHour + currentHotel.MinutesToRoundUp)
                                        {
                                            isDayNightLateCheckOutToFullDay = true;
                                        }
                                        else
                                        {
                                            hourDayNightLateCheckout = (int)dayNightLateCheckOutList[dayNightLateCheckOutList.Count - 1].NumberOfHour / 60;
                                        }
                                    }
                                }

                                if (!isDayNightLateCheckOutToFullDay)
                                {
                                    var dayNightAdjustment = planDetail.UseDayNightPrice.adjustment.Find(adj => adj.NumberOfHour == hourDayNightLateCheckout);
                                    if (dayNightAdjustment != null)
                                    {
                                        valueAfterTempDayNight = valueAfterTempDayNight + dayNightAdjustment.Price;
                                        hourRemainByDayNightPriceFormula.FormulaLateCheckOut = new Dictionary<int, decimal>();
                                        hourRemainByDayNightPriceFormula.FormulaLateCheckOut.Add(hourDayNightLateCheckout, dayNightAdjustment.Price);
                                    }
                                    else
                                    {
                                        //Warning there are no day night late check out list match
                                    }
                                }
                                else
                                {
                                    valueAfterTempDayNight = valueAfterTempDayNight + planDetail.UseDayNightPrice.price ?? 0.0M;
                                    hourRemainByDayNightPriceFormula.FormulaLateCheckOut = new Dictionary<int, decimal>();
                                    hourRemainByDayNightPriceFormula.FormulaLateCheckOut.Add(Int32.MaxValue, planDetail.UseDayNightPrice.price ?? 0.0M);
                                }
                            }
                            else
                            {
                                //Warning there are no day night late check out list
                            }
                        }
                        //}

                        valueAfterTempDayNight = valueAfterTempDayNight + planDetail.UseDayNightPrice.price ?? 0.0M;
                        hourRemainByDayNightPriceFormula.ValueAfter = valueAfterTempDayNight;
                        if (result.availableHourlyFormula == null || result.availableHourlyFormula.Count == 0)
                        {
                            result.availableHourlyFormula = new List<PlanListConstantlyFormula>();
                        }
                        result.availableHourlyFormula.Add(hourRemainByDayNightPriceFormula);

                        // Hourly Remain By DayNight
                    }//Range Hour Must Be in DayNight Time Range
                }// UseDayNightPrice

                //Determine Min Price
                if (result.availableHourlyFormula != null && result.availableHourlyFormula.Count > 0)
                {
                    decimal minPrice;
                    minPrice = (Math.Min(Math.Min(hourRemainByHourlyPriceFormula.ValueAfter, hourRemainByFullDayPriceFormula.ValueAfter), hourRemainByDayNightPriceFormula.ValueAfter));
                    result.finalHourlyFormula = new PlanListConstantlyFormula();
                    if (minPrice == hourRemainByHourlyPriceFormula.ValueAfter)
                    {
                        result.finalHourlyFormula = hourRemainByHourlyPriceFormula;
                    }
                    else if (minPrice == hourRemainByDayNightPriceFormula.ValueAfter)
                    {
                        result.finalHourlyFormula = hourRemainByDayNightPriceFormula;
                    }
                    else
                    {
                        result.finalHourlyFormula = hourRemainByFullDayPriceFormula;
                    }

                    result.finalHourlyFormula.ValueBefore = totalPrice;
                    result.finalHourlyFormula.Range = rangeHour;
                }
            }
            return result;
        }

        public void CalculateHourlyFormula()
        {
            PlanViewModel plan = null;
            if (this.model.RoomPriceId > 0)
            {
                plan = this.GetPlan();
            }
            if (plan == null)
            {
                return;
            }
            else
            {
                if (this.rangeHour != null)
                {
                    this.planListHourlyFormula = this.CalculateRangeHourInPlan(plan, this.rangeHour);
                    if (this.planListHourlyFormula.finalHourlyFormula != null)
                    {
                        this.totalPrice = this.planListHourlyFormula.finalHourlyFormula.ValueAfter;
                    }
                }
                else
                {
                    this.planListHourlyFormula = this.CalculateRangeHourInPlan(plan, this.rangeDay);
                    if (this.planListHourlyFormula.finalHourlyFormula != null)
                    {
                        this.totalPrice = this.planListHourlyFormula.finalHourlyFormula.ValueAfter;
                    }
                };
            }
        }

        public void CalculateDiscount()
        {
            this.discountPercentageAmount = this.totalPrice * (decimal)this.model.DiscountPercentage / 100;
            this.discountFlatAmount = this.model.DiscountFlat;
            this.totalPrice = this.totalPrice - (this.discountPercentageAmount + this.discountFlatAmount);
        }

        public void CalculateExtraAdultFormula()
        {
            PlanViewModel plan = null;
            if (this.model.RoomPriceId > 0)
            {
                plan = this.GetPlan();
            }
            if (plan == null)
            {
                return;
            }
            else
            {
                if (this.model.adults > this.model.currentRoomType.roomType.DefaultAdults)
                {
                    PlanDetailViewModel planDetail = null;
                    for (int i = 0; i < this.model.currentRoomType.planDetailList.Count; i++)
                    {
                        if (this.model.currentRoomType.planDetailList[i].Plan.RoomPriceId == plan.RoomPriceId)
                        {
                            planDetail = this.model.currentRoomType.planDetailList[i];
                            break;
                        }
                    }
                    if (planDetail != null && planDetail.UseExtraAdultPrice.isUsed)
                    {
                        this.extraAdults = new PlanListExtraTraveller();
                        this.extraAdults.Plan = plan;
                        this.extraAdults.Extra = this.model.adults - this.model.currentRoomType.roomType.DefaultAdults;
                        this.extraAdults.DefaultPrice = planDetail.UseExtraAdultPrice.extraAdultPrice ?? 0;
                        this.extraAdults.ExtraPrice = this.extraAdults.Extra * this.extraAdults.DefaultPrice;
                        this.totalPrice = totalPrice + this.extraAdults.ExtraPrice;
                    }
                    else
                    {
                        return;
                    }
                }
                else
                {
                    return;
                }
            }
        }

        public void CalculateExtraChildrenFormula()
        {
            PlanViewModel plan = null;
            if (this.model.RoomPriceId > 0)
            {
                plan = this.GetPlan();
            }
            if (plan == null)
            {
                return;
            }
            else
            {
                if (this.model.children > this.model.currentRoomType.roomType.DefaultChilds)
                {
                    PlanDetailViewModel planDetail = null;
                    for (int i = 0; i < this.model.currentRoomType.planDetailList.Count; i++)
                    {
                        if (this.model.currentRoomType.planDetailList[i].Plan.RoomPriceId == plan.RoomPriceId)
                        {
                            planDetail = this.model.currentRoomType.planDetailList[i];
                            break;
                        }
                    }
                    if (planDetail != null && planDetail.UseExtraChildPrice.isUsed)
                    {
                        this.extraChildren = new PlanListExtraTraveller();
                        this.extraChildren.Plan = plan;
                        this.extraChildren.Extra = this.model.children - this.model.currentRoomType.roomType.DefaultChilds;
                        this.extraChildren.DefaultPrice = planDetail.UseExtraChildPrice.extraChildPrice ?? 0;
                        this.extraChildren.ExtraPrice = this.extraChildren.Extra * this.extraChildren.DefaultPrice;
                        this.totalPrice = totalPrice + this.extraChildren.ExtraPrice;
                    }
                    else
                    {
                        return;
                    }
                }
                else
                {
                    return;
                }
            }
        }
    }

    public class RoomPriceUtilities
    {
        public static PlanListPreviewModel createRoomPriceModel(CalculateRoomPrice model)
        {
            var context = new ezCloudDataContext();
            var currentClientUser = UserUtitily.getUserProfile();
            var room = new Rooms();
            if (model.roomTypeId > 0)
            {
                //room = context.Rooms.Where(rm => rm.HotelId == currentClientUser.HotelId && rm.RoomId == model.roomId).FirstOrDefault();
                RoomTypes roomType = context.RoomTypes.Where(rt => rt.HotelId == currentClientUser.HotelId && rt.RoomTypeId == model.roomTypeId).FirstOrDefault();
                CurrentRoomType currentRoomType = new CurrentRoomType();
                RoomPrices roomPrice = context.RoomPrices.Where(rp => rp.HotelId == currentClientUser.HotelId && rp.RoomPriceId == model.RoomPriceId).FirstOrDefault();
                if (roomPrice != null)
                {
                    currentRoomType.roomType = context.RoomTypes.Where(rt => rt.HotelId == currentClientUser.HotelId && rt.RoomTypeId == roomPrice.RoomTypeId).FirstOrDefault();
                }
                //currentRoomType.roomType = context.RoomTypes.Where(rt => rt.HotelId == currentClientUser.HotelId && rt.RoomTypeId == roomType.RoomTypeId).FirstOrDefault();
                currentRoomType.planList = new List<PlanViewModel>();
                currentRoomType.planDetailList = new List<PlanDetailViewModel>();
                List<RoomPrices> roomPriceList = context.RoomPrices.Where(rp => rp.HotelId == currentClientUser.HotelId && rp.RoomTypeId == currentRoomType.roomType.RoomTypeId).ToList();
                for (int i = 0; i < roomPriceList.Count; i++)
                {
                    PlanViewModel planTemp = new PlanViewModel();
                    planTemp.RoomPriceId = roomPriceList[i].RoomPriceId;
                    planTemp.RoomPriceName = roomPriceList[i].RoomPriceName;
                    planTemp.Priority = roomPriceList[i].Priority;
                    planTemp.HotelId = roomPriceList[i].HotelId ?? default(int);
                    planTemp.RoomPriceId = roomPriceList[i].RoomPriceId;
                    planTemp.isActive = roomPriceList[i].IsActive;
                    currentRoomType.planList.Add(planTemp);
                    PlanDetailViewModel planDetailTemp = new PlanDetailViewModel();
                    planDetailTemp.Plan = planTemp;
                    planDetailTemp.PlanSchedule = new PlanSchedule();
                    planDetailTemp.PlanSchedule.ApplyOnMonday = roomPriceList[i].ApplyOnMonday;
                    planDetailTemp.PlanSchedule.ApplyOnTuesday = roomPriceList[i].ApplyOnTuesday;
                    planDetailTemp.PlanSchedule.ApplyOnWednesday = roomPriceList[i].ApplyOnWednesday;
                    planDetailTemp.PlanSchedule.ApplyOnThursday = roomPriceList[i].ApplyOnThursday;
                    planDetailTemp.PlanSchedule.ApplyOnFriday = roomPriceList[i].ApplyOnFriday;
                    planDetailTemp.PlanSchedule.ApplyOnSaturday = roomPriceList[i].ApplyOnSaturday;
                    planDetailTemp.PlanSchedule.ApplyOnSunday = roomPriceList[i].ApplyOnSunday;
                    planDetailTemp.PlanSchedule.startDate = roomPriceList[i].StartDate;
                    planDetailTemp.PlanSchedule.endDate = roomPriceList[i].EndDate;

                    planDetailTemp.UseHourlyPrice = new UseHourlyPrice();
                    planDetailTemp.UseHourlyPrice.name = "USE_HOURLY_PRICE";
                    planDetailTemp.UseHourlyPrice.property = "UseHourlyPrice";
                    planDetailTemp.UseHourlyPrice.adjustmentCode = "HOURLY_PRICE";
                    planDetailTemp.UseHourlyPrice.isUsed = roomPriceList[i].UseHourlyPrice;
                    planDetailTemp.UseHourlyPrice.adjustment = new List<PriceAdjustment>();
                    List<RoomPriceAdjustment> hourlyPriceAdjustment = context.RoomPriceAdjustment.Where(rpa => rpa.HotelId == currentClientUser.HotelId && rpa.RoomPriceId == roomPriceList[i].RoomPriceId && rpa.AdjustmentCode == "HOURLY_PRICE").ToList();
                    for (int j = 0; j < hourlyPriceAdjustment.Count; j++)
                    {
                        PriceAdjustment priceAdjustmentTemp = new PriceAdjustment();
                        priceAdjustmentTemp.RoomPriceAdjustmentId = hourlyPriceAdjustment[j].RoomPriceAdjustmentId;
                        priceAdjustmentTemp.RoomPriceId = hourlyPriceAdjustment[j].RoomPriceId;
                        priceAdjustmentTemp.NumberOfHour = (int)hourlyPriceAdjustment[j].NumberOfHour;
                        priceAdjustmentTemp.Price = hourlyPriceAdjustment[j].Price ?? 0;
                        priceAdjustmentTemp.AdjustmentCode = hourlyPriceAdjustment[j].AdjustmentCode;
                        planDetailTemp.UseHourlyPrice.adjustment.Add(priceAdjustmentTemp);
                    }

                    planDetailTemp.UseWeeklyPrice = new UseWeeklyPrice();
                    planDetailTemp.UseWeeklyPrice.name = "USE_WEEKLY_PRICE";
                    planDetailTemp.UseWeeklyPrice.property = "UseWeeklyPrice";
                    planDetailTemp.UseWeeklyPrice.adjustmentCode = "OVERDUE_WEEKLY";
                    planDetailTemp.UseWeeklyPrice.isUsed = roomPriceList[i].UseWeeklyPrice;
                    planDetailTemp.UseWeeklyPrice.price = roomPriceList[i].WeeklyPrice;
                    planDetailTemp.UseWeeklyPrice.adjustment = new List<PriceAdjustment>();

                    planDetailTemp.UseMonthlyPrice = new UseMonthlyPrice();
                    planDetailTemp.UseMonthlyPrice.name = "USE_MONTHLY_PRICE";
                    planDetailTemp.UseMonthlyPrice.property = "UseMonthlyPrice";
                    planDetailTemp.UseMonthlyPrice.adjustmentCode = "OVERDUE_MONTHLY";
                    planDetailTemp.UseMonthlyPrice.isUsed = roomPriceList[i].UseMonthlyPrice;
                    planDetailTemp.UseMonthlyPrice.price = roomPriceList[i].MonthlyPrice;
                    planDetailTemp.UseMonthlyPrice.adjustment = new List<PriceAdjustment>();

                    planDetailTemp.UseFullDayPrice = new UseFullDayPrice();
                    planDetailTemp.UseFullDayPrice.name = "USE_FULL_DAY_PRICE";
                    planDetailTemp.UseFullDayPrice.property = "UseFullDayPrice";
                    planDetailTemp.UseFullDayPrice.adjustmentCode = "OVERDUE_FULLDAY";
                    planDetailTemp.UseFullDayPrice.isUsed = roomPriceList[i].UseFullDayPrice;
                    //planDetailTemp.UseFullDayPrice.price = roomPriceList[i].FullDayPrice;
                    planDetailTemp.UseFullDayPrice.price = model.Price;
                    planDetailTemp.UseFullDayPrice.adjustment = new List<PriceAdjustment>();

                    List<RoomPriceAdjustment> fullDayPriceAdjustment = context.RoomPriceAdjustment.Where(rpa => rpa.HotelId == currentClientUser.HotelId && rpa.RoomPriceId == roomPriceList[i].RoomPriceId && rpa.AdjustmentCode == "OVERDUE_FULLDAY").ToList();
                    for (int j = 0; j < fullDayPriceAdjustment.Count; j++)
                    {
                        PriceAdjustment priceAdjustmentTemp = new PriceAdjustment();
                        priceAdjustmentTemp.RoomPriceAdjustmentId = fullDayPriceAdjustment[j].RoomPriceAdjustmentId;
                        priceAdjustmentTemp.RoomPriceId = fullDayPriceAdjustment[j].RoomPriceId;
                        priceAdjustmentTemp.NumberOfHour = (int)fullDayPriceAdjustment[j].NumberOfHour;
                        priceAdjustmentTemp.Price = fullDayPriceAdjustment[j].Price ?? 0;
                        priceAdjustmentTemp.AdjustmentCode = fullDayPriceAdjustment[j].AdjustmentCode;
                        planDetailTemp.UseFullDayPrice.adjustment.Add(priceAdjustmentTemp);
                    }

                    planDetailTemp.UseDayNightPrice = new UseDayNightPrice();
                    planDetailTemp.UseDayNightPrice.name = "USE_DAY_NIGHT_PRICE";
                    planDetailTemp.UseDayNightPrice.property = "UseDayNightPrice";
                    planDetailTemp.UseDayNightPrice.adjustmentCode = "OVERDUE_DAYNIGHT";
                    planDetailTemp.UseDayNightPrice.isUsed = roomPriceList[i].UseDayNightPrice;
                    planDetailTemp.UseDayNightPrice.price = roomPriceList[i].DayNightPrice;
                    planDetailTemp.UseDayNightPrice.adjustment = new List<PriceAdjustment>();

                    List<RoomPriceAdjustment> dayNightPriceAdjustment = context.RoomPriceAdjustment.Where(rpa => rpa.HotelId == currentClientUser.HotelId && rpa.RoomPriceId == roomPriceList[i].RoomPriceId && rpa.AdjustmentCode == "OVERDUE_DAYNIGHT").ToList();
                    for (int j = 0; j < dayNightPriceAdjustment.Count; j++)
                    {
                        PriceAdjustment priceAdjustmentTemp = new PriceAdjustment();
                        priceAdjustmentTemp.RoomPriceAdjustmentId = dayNightPriceAdjustment[j].RoomPriceAdjustmentId;
                        priceAdjustmentTemp.RoomPriceId = dayNightPriceAdjustment[j].RoomPriceId;
                        priceAdjustmentTemp.NumberOfHour = (int)dayNightPriceAdjustment[j].NumberOfHour;
                        priceAdjustmentTemp.Price = dayNightPriceAdjustment[j].Price ?? 0;
                        priceAdjustmentTemp.AdjustmentCode = dayNightPriceAdjustment[j].AdjustmentCode;
                        planDetailTemp.UseDayNightPrice.adjustment.Add(priceAdjustmentTemp);
                    }

                    planDetailTemp.UseEarlyCheckinFullDay = new UseEarlyCheckInFullDay();
                    planDetailTemp.UseEarlyCheckinFullDay.name = "USE_EARLY_CHECKIN_FULL_DAY";
                    planDetailTemp.UseEarlyCheckinFullDay.property = "UseEarlyCheckinFullDay";
                    planDetailTemp.UseEarlyCheckinFullDay.adjustmentCode = "EARLY_CHECKIN_FULL_DAY";
                    planDetailTemp.UseEarlyCheckinFullDay.isUsed = roomPriceList[i].UseEarlyCheckinFullday;
                    planDetailTemp.UseEarlyCheckinFullDay.adjustment = new List<PriceAdjustment>();

                    List<RoomPriceAdjustment> earlyCheckinFullDayPriceAdjustment = context.RoomPriceAdjustment.Where(rpa => rpa.HotelId == currentClientUser.HotelId && rpa.RoomPriceId == roomPriceList[i].RoomPriceId && rpa.AdjustmentCode == "EARLY_CHECKIN_FULL_DAY").ToList();
                    for (int j = 0; j < earlyCheckinFullDayPriceAdjustment.Count; j++)
                    {
                        PriceAdjustment priceAdjustmentTemp = new PriceAdjustment();
                        priceAdjustmentTemp.RoomPriceAdjustmentId = earlyCheckinFullDayPriceAdjustment[j].RoomPriceAdjustmentId;
                        priceAdjustmentTemp.RoomPriceId = earlyCheckinFullDayPriceAdjustment[j].RoomPriceId;
                        priceAdjustmentTemp.NumberOfHour = (int)earlyCheckinFullDayPriceAdjustment[j].NumberOfHour;
                        priceAdjustmentTemp.Price = earlyCheckinFullDayPriceAdjustment[j].Price ?? 0;
                        priceAdjustmentTemp.AdjustmentCode = earlyCheckinFullDayPriceAdjustment[j].AdjustmentCode;
                        planDetailTemp.UseEarlyCheckinFullDay.adjustment.Add(priceAdjustmentTemp);
                    }

                    planDetailTemp.UseEarlyCheckinDayNight = new UseEarlyCheckInDayNight();
                    planDetailTemp.UseEarlyCheckinDayNight.name = "USE_EARLY_CHECKIN_DAY_NIGHT";
                    planDetailTemp.UseEarlyCheckinDayNight.property = "UseEarlyCheckinDayNight";
                    planDetailTemp.UseEarlyCheckinDayNight.adjustmentCode = "EARLY_CHECKIN_DAY_NIGHT";
                    planDetailTemp.UseEarlyCheckinDayNight.isUsed = roomPriceList[i].UseEarlyCheckinDayNight;
                    planDetailTemp.UseEarlyCheckinDayNight.adjustment = new List<PriceAdjustment>();

                    List<RoomPriceAdjustment> earlyCheckinDayNightPriceAdjustment = context.RoomPriceAdjustment.Where(rpa => rpa.HotelId == currentClientUser.HotelId && rpa.RoomPriceId == roomPriceList[i].RoomPriceId && rpa.AdjustmentCode == "EARLY_CHECKIN_DAY_NIGHT").ToList();
                    for (int j = 0; j < earlyCheckinDayNightPriceAdjustment.Count; j++)
                    {
                        PriceAdjustment priceAdjustmentTemp = new PriceAdjustment();
                        priceAdjustmentTemp.RoomPriceAdjustmentId = earlyCheckinDayNightPriceAdjustment[j].RoomPriceAdjustmentId;
                        priceAdjustmentTemp.RoomPriceId = earlyCheckinDayNightPriceAdjustment[j].RoomPriceId;
                        priceAdjustmentTemp.NumberOfHour = (int)earlyCheckinDayNightPriceAdjustment[j].NumberOfHour;
                        priceAdjustmentTemp.Price = earlyCheckinDayNightPriceAdjustment[j].Price ?? 0;
                        priceAdjustmentTemp.AdjustmentCode = earlyCheckinDayNightPriceAdjustment[j].AdjustmentCode;
                        planDetailTemp.UseEarlyCheckinDayNight.adjustment.Add(priceAdjustmentTemp);
                    }

                    planDetailTemp.UseExtraAdultPrice = new UseExtraAdultPrice();
                    planDetailTemp.UseExtraAdultPrice.name = "USE_EXTRA_ADULT_PRICE";
                    planDetailTemp.UseExtraAdultPrice.property = "UseExtraAdultPrice";
                    planDetailTemp.UseExtraAdultPrice.isUsed = roomPriceList[i].UseExtraAdultPrice;
                    planDetailTemp.UseExtraAdultPrice.extraAdultPrice = roomPriceList[i].ExtraAdultPrice;

                    planDetailTemp.UseExtraChildPrice = new UseExtraChildPrice();
                    planDetailTemp.UseExtraChildPrice.name = "USE_EXTRA_CHILD_PRICE";
                    planDetailTemp.UseExtraChildPrice.property = "UseExtraChildPrice";
                    planDetailTemp.UseExtraChildPrice.isUsed = roomPriceList[i].UseExtraChildPrice;
                    planDetailTemp.UseExtraChildPrice.extraChildPrice = roomPriceList[i].ExtraChildPrice;

                    currentRoomType.planDetailList.Add(planDetailTemp);
                }

                PlanListPreviewModel calculateModel = new PlanListPreviewModel();
                calculateModel.previewStartDate = model.arrivalDate;
                calculateModel.previewEndDate = model.departureDate;
                calculateModel.adults = model.adults;
                calculateModel.children = model.children;
                calculateModel.RoomPriceId = model.RoomPriceId ?? 0;
                calculateModel.FOC = model.FOC;
                calculateModel.DiscountPercentage = model.DiscountPercentage;
                calculateModel.DiscountFlat = model.DiscountFlat;
                calculateModel.currentRoomType = currentRoomType;

                return calculateModel;
            }
            else
            {
                return null;
            }
        }

        public static async Task<PlanListDateRange> CalculateRoomPriceBase(CalculateRoomPrice model)
        {
            PlanListPreviewModel calculateModel = createRoomPriceModel(model);
            if (calculateModel != null)
            {
                PlanListDateRange planListDateRange = new PlanListDateRange(calculateModel.previewStartDate, calculateModel.previewEndDate);
                planListDateRange.model = calculateModel;
                planListDateRange.CalculateTimeDuration();
                planListDateRange.CalculateConstantlyFormula();
                if (planListDateRange.totalHour * 60 >= planListDateRange.hotelTotalWorkTime)
                {
                    planListDateRange.CalculateFullDayFormula();
                }
                else
                {
                    planListDateRange.CalculateHourlyFormula();
                }
                
                planListDateRange.CalculateExtraAdultFormula();
                planListDateRange.CalculateExtraChildrenFormula();
                return planListDateRange;
            }
            else
            {
                return null;
            }
        }

        public static async Task<PlanListDateRange> CalculateRoomPrice(CalculateRoomPrice model)
        {
            var startTime = DateTime.Now;
            var context = new ezCloudDataContext();
            var user = UserUtitily.getUserProfile();
            var currentHotel = context.Hotels.Where(ht => ht.HotelId == user.HotelId).FirstOrDefault();
            var currentRR = new ReservationRooms();
            if (model.reservationRoomId != 0)
            {
                currentRR = currentHotel.ReservationRoomsList.Where(rr => rr.HotelId == user.HotelId && rr.ReservationRoomId == model.reservationRoomId).FirstOrDefault();
                if (currentRR.BookingStatus == "CHECKOUT" || currentRR.BookingStatus == "CANCEL")
                {
                    model.departureDate = (DateTime)currentRR.DepartureDate;
                }

                //Update adults,children: need to get max Adults, children from reservation
                var listReservationTravellerExtraInformation = currentHotel.ReservationTravellerExtraInformationList.Where(t => t.HotelId == user.HotelId)
                   .Join(context.ReservationTravellers.Where(t => t.ReservationRoomId == model.reservationRoomId), rt => rt.ReservationTravellerId, rtei => rtei.ReservationTravellerId, (rt, rtei) => new { rt.ReservationTravellers.ReservationRoomId, rt.IsChild }).ToList();
                var countAdult = 0;
                var countChild = 0;
                if (listReservationTravellerExtraInformation != null && listReservationTravellerExtraInformation.Count > 0)
                {
                     countAdult = listReservationTravellerExtraInformation.Where(rt => rt.IsChild == false).ToList().Count();
                     countChild = listReservationTravellerExtraInformation.Where(rt => rt.IsChild == true).ToList().Count();
                }

                var adults = Math.Max((int)countAdult, currentRR.Adults);
                var children = Math.Max((int)countChild, currentRR.Child);

                model.adults = adults;
                model.children = children;

            }

            var planListDateRangeTask = CalculateRoomPriceBase(model);
            
            if (currentRR == null || (currentRR != null && currentRR.RoomPrices.UseHourlyPrice == true))
            {
                await Task.WhenAll(planListDateRangeTask);

                var planListDateRange = planListDateRangeTask.Result;


                if (model.FOC == true)
                {
                    planListDateRange.focAmount = -planListDateRange.totalPrice;
                    planListDateRange.totalPrice = 0;

                }
                else
                {
                    planListDateRange.discountPercentageAmount = planListDateRange.totalPrice * (decimal)planListDateRange.model.DiscountPercentage / 100;
                    planListDateRange.discountFlatAmount = planListDateRange.model.DiscountFlat;
                    planListDateRange.totalPrice = planListDateRange.totalPrice - (planListDateRange.discountPercentageAmount + planListDateRange.discountFlatAmount);
                }
                return planListDateRange;
            }
            else
            {
                var roomCharges = currentRR.RoomChargesList;
                CalculateRoomPrice modelTemp = new CalculateRoomPrice();
                modelTemp.roomId = model.roomId;
                modelTemp.reservationRoomId = model.reservationRoomId;
                modelTemp.adults = model.adults;
                modelTemp.children = model.children;
                modelTemp.RoomPriceId = model.RoomPriceId;
                modelTemp.FOC = model.FOC;
                modelTemp.DiscountFlat = model.DiscountFlat;
                modelTemp.DiscountPercentage = model.DiscountPercentage;
                modelTemp.languageKeys = model.languageKeys;
                modelTemp.Price = model.Price;
                modelTemp.roomTypeId = model.roomTypeId;
                modelTemp.arrivalDate = model.arrivalDate;
                modelTemp.departureDate = currentRR.DepartureDate.Value;

                
                var planListDateRangeTempTask = CalculateRoomPriceBase(modelTemp);//need to improve
                await Task.WhenAll(planListDateRangeTempTask,planListDateRangeTask);
                var planListDateRangeTemp = planListDateRangeTempTask.Result;
                var planListDateRange = planListDateRangeTask.Result;
                
                var roomChargesDict = roomCharges.ToDictionary(rc => rc.StartDate.Value.AddMinutes(currentHotel.TimeZoneOffset).Date, rc => rc);
                // Build Actual Total Price
                if (planListDateRangeTemp.planListFullDayFormula != null && planListDateRangeTemp.planListFullDayFormula.Count > 0)
                {
                    
                    for (var i = 0; i < planListDateRangeTemp.planListFullDayFormula.Count; i++)
                    {
                        var formulaTemp = planListDateRangeTemp.planListFullDayFormula[i];
                        //var roomChargeTemp = roomCharges.FirstOrDefault(rc => rc.StartDate.Value.AddMinutes(currentHotel.TimeZoneOffset).Date == formulaTemp.formula.Range.Start.AddMinutes(currentHotel.TimeZoneOffset).Date);
                        var roomChargeTemp = roomChargesDict.ContainsKey(formulaTemp.formula.Range.Start.AddMinutes(currentHotel.TimeZoneOffset).Date) ?roomChargesDict[formulaTemp.formula.Range.Start.AddMinutes(currentHotel.TimeZoneOffset).Date]:null;
                        if (roomChargeTemp != null)
                        {
                            var diffTotalPrice = roomChargeTemp.Amount - formulaTemp.formula.FormulaValue;
                            planListDateRangeTemp.totalPrice = planListDateRangeTemp.totalPrice + diffTotalPrice.Value;
                        }
                    }
                }
                
                if (planListDateRangeTemp.planListHourlyFormula != null && planListDateRangeTemp.planListHourlyFormula.finalHourlyFormula != null
                    && planListDateRangeTemp.planListHourlyFormula.finalHourlyFormula.Name == "FULL_DAY_PRICE")
                {
                    var formulaTemp = planListDateRangeTemp.planListHourlyFormula.finalHourlyFormula;
                    var roomChargeTemp = roomChargesDict.ContainsKey(formulaTemp.Range.Start.AddMinutes(currentHotel.TimeZoneOffset).Date) ? roomChargesDict[formulaTemp.Range.Start.AddMinutes(currentHotel.TimeZoneOffset).Date] : null; ;
                    
                    if (roomChargeTemp != null)
                    {
                        var diffTotalPrice = roomChargeTemp.Amount - formulaTemp.FormulaValue;
                        planListDateRangeTemp.totalPrice = planListDateRangeTemp.totalPrice + diffTotalPrice.Value;
                    }
                }
                
                if (modelTemp.FOC == true)
                {
                    planListDateRangeTemp.focAmount = -planListDateRangeTemp.totalPrice;
                    planListDateRangeTemp.totalPrice = 0;
                   
                }
                else
                {
                    planListDateRangeTemp.discountPercentageAmount = planListDateRangeTemp.totalPrice * (decimal)planListDateRangeTemp.model.DiscountPercentage / 100;
                    planListDateRangeTemp.discountFlatAmount = planListDateRangeTemp.model.DiscountFlat;
                    planListDateRangeTemp.totalPrice = planListDateRangeTemp.totalPrice - (planListDateRangeTemp.discountPercentageAmount + planListDateRangeTemp.discountFlatAmount);
                }
                
                // Build Current Total Price
                if (planListDateRange.planListFullDayFormula != null && planListDateRange.planListFullDayFormula.Count > 0)
                {
                    for (var i = 0; i < planListDateRange.planListFullDayFormula.Count; i++)
                    {
                        var formulaTemp = planListDateRange.planListFullDayFormula[i];
                        var roomChargeTemp = roomChargesDict.ContainsKey(formulaTemp.formula.Range.Start.AddMinutes(currentHotel.TimeZoneOffset).Date) ? roomChargesDict[formulaTemp.formula.Range.Start.AddMinutes(currentHotel.TimeZoneOffset).Date]:null;
                        if (roomChargeTemp != null)
                        {
                            var diffTotalPrice = roomChargeTemp.Amount - formulaTemp.formula.FormulaValue;
                            formulaTemp.formula.FormulaValue = roomChargeTemp.Amount.Value;
                            formulaTemp.formula.ValueAfter = formulaTemp.formula.ValueBefore + formulaTemp.formula.FormulaValue;
                            planListDateRange.totalPrice = planListDateRange.totalPrice + diffTotalPrice.Value;
                        }
                    }
                }


                if (planListDateRange.planListHourlyFormula != null && planListDateRange.planListHourlyFormula.finalHourlyFormula != null 
                    && planListDateRange.planListHourlyFormula.finalHourlyFormula.Name== "FULL_DAY_PRICE")

                {
                    var formulaTemp = planListDateRange.planListHourlyFormula.finalHourlyFormula;
                    var roomChargeTemp = roomChargesDict.ContainsKey(formulaTemp.Range.Start.AddMinutes(currentHotel.TimeZoneOffset).Date) ?roomChargesDict[formulaTemp.Range.Start.AddMinutes(currentHotel.TimeZoneOffset).Date]:null;
                    if (roomChargeTemp != null)
                    {
                        var diffTotalPrice = roomChargeTemp.Amount - formulaTemp.FormulaValue;
                        formulaTemp.FormulaValue = roomChargeTemp.Amount.Value;
                        formulaTemp.ValueAfter = formulaTemp.ValueBefore + formulaTemp.FormulaValue;
                        planListDateRange.totalPrice = planListDateRange.totalPrice + diffTotalPrice.Value;
                    }
                }
                
                if (model.FOC == true)
                {
                    planListDateRange.focAmount = -planListDateRange.totalPrice;
                    planListDateRange.totalPrice = 0;
                   
                }
                else
                {
                    planListDateRange.discountPercentageAmount = planListDateRange.totalPrice * (decimal)planListDateRange.model.DiscountPercentage / 100;
                    planListDateRange.discountFlatAmount = planListDateRange.model.DiscountFlat;
                    planListDateRange.totalPrice = planListDateRange.totalPrice - (planListDateRange.discountPercentageAmount + planListDateRange.discountFlatAmount);
                }
                
                planListDateRange.actualPlanListDateRange = planListDateRangeTemp;
                return planListDateRange;
            }
        }
    }
}